diff options
Diffstat (limited to 'tests/UsageReportingTest')
-rw-r--r-- | tests/UsageReportingTest/Android.mk | 17 | ||||
-rw-r--r-- | tests/UsageReportingTest/AndroidManifest.xml | 22 | ||||
-rw-r--r-- | tests/UsageReportingTest/res/layout/row_item.xml | 36 | ||||
-rw-r--r-- | tests/UsageReportingTest/res/menu/main.xml | 28 | ||||
-rw-r--r-- | tests/UsageReportingTest/res/values/colors.xml | 19 | ||||
-rw-r--r-- | tests/UsageReportingTest/res/values/strings.xml | 47 | ||||
-rw-r--r-- | tests/UsageReportingTest/res/values/styles.xml | 31 | ||||
-rw-r--r-- | tests/UsageReportingTest/src/com/android/tests/usagereporter/UsageReporterActivity.java | 320 |
8 files changed, 520 insertions, 0 deletions
diff --git a/tests/UsageReportingTest/Android.mk b/tests/UsageReportingTest/Android.mk new file mode 100644 index 000000000000..afb6e16b1fdf --- /dev/null +++ b/tests/UsageReportingTest/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +# Only compile source java files in this apk. +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_USE_AAPT2 := true +LOCAL_STATIC_ANDROID_LIBRARIES := androidx.legacy_legacy-support-v4 + +LOCAL_CERTIFICATE := platform + +LOCAL_PACKAGE_NAME := UsageReportingTest +LOCAL_PRIVATE_PLATFORM_APIS := true + +include $(BUILD_PACKAGE) diff --git a/tests/UsageReportingTest/AndroidManifest.xml b/tests/UsageReportingTest/AndroidManifest.xml new file mode 100644 index 000000000000..be0b09e972a5 --- /dev/null +++ b/tests/UsageReportingTest/AndroidManifest.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + Note: Add android:sharedUserId="android.uid.system" to the root element to simulate the system UID + caller case. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.tests.usagereporter" + > + + <application android:label="@string/reporter_app"> + <activity android:name="UsageReporterActivity" + android:label="UsageReporter"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + </application> +</manifest> diff --git a/tests/UsageReportingTest/res/layout/row_item.xml b/tests/UsageReportingTest/res/layout/row_item.xml new file mode 100644 index 000000000000..1eb2dab29124 --- /dev/null +++ b/tests/UsageReportingTest/res/layout/row_item.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:background="@color/inactive_color"> + + <TextView android:id="@+id/token" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textStyle="bold"/> + + <Button android:id="@+id/start" style="@style/ActionButton" + android:text="@string/start" /> + + <Button android:id="@+id/stop" style="@style/ActionButton" + android:text="@string/stop" /> +</LinearLayout> diff --git a/tests/UsageReportingTest/res/menu/main.xml b/tests/UsageReportingTest/res/menu/main.xml new file mode 100644 index 000000000000..9847c2dce8f2 --- /dev/null +++ b/tests/UsageReportingTest/res/menu/main.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/add_token" + android:title="@string/add_token"/> + <item android:id="@+id/add_many_tokens" + android:title="@string/add_many_tokens"/> + <item android:id="@+id/stop_all" + android:title="@string/stop_all_tokens"/> + <group android:checkableBehavior="all"> + <item android:id="@+id/restore_on_start" + android:title="@string/restore_tokens_on_start"/> + </group> +</menu>
\ No newline at end of file diff --git a/tests/UsageReportingTest/res/values/colors.xml b/tests/UsageReportingTest/res/values/colors.xml new file mode 100644 index 000000000000..03bcf8a60182 --- /dev/null +++ b/tests/UsageReportingTest/res/values/colors.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> + <color name="active_color">#FFF</color> + <color name="inactive_color">#AAA</color> +</resources>
\ No newline at end of file diff --git a/tests/UsageReportingTest/res/values/strings.xml b/tests/UsageReportingTest/res/values/strings.xml new file mode 100644 index 000000000000..015290e732a0 --- /dev/null +++ b/tests/UsageReportingTest/res/values/strings.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <!-- Do not translate --> + <string name="reporter_app">Usage Reporter App</string> + <!-- Do not translate --> + <string name="start">Start</string> + <!-- Do not translate --> + <string name="stop">Stop</string> + <!-- Do not translate --> + <string name="default_token">SuperSecretToken</string> + + <!-- Do not translate --> + <string name="add_token">Add Token</string> + <!-- Do not translate --> + <string name="add_many_tokens">Add Many Tokens</string> + <!-- Do not translate --> + <string name="stop_all_tokens">Stop All</string> + <!-- Do not translate --> + <string name="restore_tokens_on_start">Readd Tokens on Start</string> + + + <!-- Do not translate --> + <string name="token_query">Enter token(s) (delimit tokens with commas)</string> + <!-- Do not translate --> + <string name="many_tokens_query">Generate how many tokens?</string> + <!-- Do not translate --> + <string name="stop_all_tokens_query">Stop all tokens?</string> + <!-- Do not translate --> + <string name="ok">OK</string> + <!-- Do not translate --> + <string name="cancel">Cancel</string> +</resources>
\ No newline at end of file diff --git a/tests/UsageReportingTest/res/values/styles.xml b/tests/UsageReportingTest/res/values/styles.xml new file mode 100644 index 000000000000..e5b86c5e836b --- /dev/null +++ b/tests/UsageReportingTest/res/values/styles.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <style name="ActionButton"> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:textAppearance">@style/TextAppearance.ActionButton</item> + </style> + + <style name="TextAppearance" parent="android:TextAppearance"> + </style> + + <style name="TextAppearance.ActionButton"> + <item name="android:textStyle">italic</item> + </style> + +</resources> diff --git a/tests/UsageReportingTest/src/com/android/tests/usagereporter/UsageReporterActivity.java b/tests/UsageReportingTest/src/com/android/tests/usagereporter/UsageReporterActivity.java new file mode 100644 index 000000000000..946be8fe93d3 --- /dev/null +++ b/tests/UsageReportingTest/src/com/android/tests/usagereporter/UsageReporterActivity.java @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.tests.usagereporter; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ListActivity; +import android.app.usage.UsageStatsManager; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.text.InputType; +import android.text.TextUtils; +import android.util.ArraySet; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.ArrayList; + +public class UsageReporterActivity extends ListActivity { + + private Activity mActivity; + private final ArrayList<String> mTokens = new ArrayList(); + private final ArraySet<String> mActives = new ArraySet(); + private UsageStatsManager mUsageStatsManager; + private Adapter mAdapter; + private boolean mRestoreOnStart = false; + private static Context sContext; + + /** Called with the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + sContext = getApplicationContext(); + + mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE); + + mAdapter = new Adapter(); + setListAdapter(mAdapter); + } + + @Override + protected void onStart() { + super.onStart(); + mActivity = this; + + + if (mRestoreOnStart) { + ArrayList<String> removed = null; + for (String token : mActives) { + try { + mUsageStatsManager.reportUsageStart(mActivity, token); + } catch (Exception e) { + // Somthing went wrong, recover and move on + if (removed == null) { + removed = new ArrayList(); + } + removed.add(token); + } + } + if (removed != null) { + for (String token : removed) { + mActives.remove(token); + } + } + } else { + mActives.clear(); + } + } + + /** + * Called when the activity is about to start interacting with the user. + */ + @Override + protected void onResume() { + super.onResume(); + mAdapter.notifyDataSetChanged(); + } + + + /** + * Called when your activity's options menu needs to be created. + */ + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.main, menu); + return super.onCreateOptionsMenu(menu); + } + + + /** + * Called when a menu item is selected. + */ + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.add_token: + callAddToken(); + return true; + case R.id.add_many_tokens: + callAddManyTokens(); + return true; + case R.id.stop_all: + callStopAll(); + return true; + case R.id.restore_on_start: + mRestoreOnStart = !mRestoreOnStart; + item.setChecked(mRestoreOnStart); + return true; + } + + return super.onOptionsItemSelected(item); + } + + private void callAddToken() { + final AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.token_query)); + final EditText input = new EditText(this); + input.setInputType(InputType.TYPE_CLASS_TEXT); + input.setHint(getString(R.string.default_token)); + builder.setView(input); + + builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String tokenNames = input.getText().toString().trim(); + if (TextUtils.isEmpty(tokenNames)) { + tokenNames = getString(R.string.default_token); + } + String[] tokens = tokenNames.split(","); + for (String token : tokens) { + if (mTokens.contains(token)) continue; + mTokens.add(token); + } + mAdapter.notifyDataSetChanged(); + + } + }); + builder.setNegativeButton(getString(R.string.cancel), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + builder.show(); + } + + private void callAddManyTokens() { + final AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.many_tokens_query)); + final EditText input = new EditText(this); + input.setInputType(InputType.TYPE_CLASS_NUMBER); + builder.setView(input); + + builder.setPositiveButton(getString(R.string.ok), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String val = input.getText().toString().trim(); + if (TextUtils.isEmpty(val)) return; + int n = Integer.parseInt(val); + for (int i = 0; i < n; i++) { + final String token = getString(R.string.default_token) + i; + if (mTokens.contains(token)) continue; + mTokens.add(token); + } + mAdapter.notifyDataSetChanged(); + + } + }); + builder.setNegativeButton(getString(R.string.cancel), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + builder.show(); + } + + private void callStopAll() { + final AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.stop_all_tokens_query)); + + builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + for (String token : mActives) { + mUsageStatsManager.reportUsageStop(mActivity, token); + } + mActives.clear(); + mAdapter.notifyDataSetChanged(); + } + }); + builder.setNegativeButton(getString(R.string.cancel), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + builder.show(); + } + + /** + * A call-back for when the user presses the back button. + */ + OnClickListener mStartListener = new OnClickListener() { + public void onClick(View v) { + final View parent = (View) v.getParent(); + final String token = ((TextView) parent.findViewById(R.id.token)).getText().toString(); + try { + mUsageStatsManager.reportUsageStart(mActivity, token); + } catch (Exception e) { + Toast.makeText(sContext, e.toString(), Toast.LENGTH_LONG).show(); + } + parent.setBackgroundColor(getColor(R.color.active_color)); + mActives.add(token); + } + }; + + /** + * A call-back for when the user presses the clear button. + */ + OnClickListener mStopListener = new OnClickListener() { + public void onClick(View v) { + final View parent = (View) v.getParent(); + + final String token = ((TextView) parent.findViewById(R.id.token)).getText().toString(); + try { + mUsageStatsManager.reportUsageStop(mActivity, token); + } catch (Exception e) { + Toast.makeText(sContext, e.toString(), Toast.LENGTH_LONG).show(); + } + parent.setBackgroundColor(getColor(R.color.inactive_color)); + mActives.remove(token); + } + }; + + + private class Adapter extends BaseAdapter { + @Override + public int getCount() { + return mTokens.size(); + } + + @Override + public Object getItem(int position) { + return mTokens.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final ViewHolder holder; + if (convertView == null) { + convertView = LayoutInflater.from(UsageReporterActivity.this) + .inflate(R.layout.row_item, parent, false); + holder = new ViewHolder(); + holder.tokenName = (TextView) convertView.findViewById(R.id.token); + + holder.startButton = ((Button) convertView.findViewById(R.id.start)); + holder.startButton.setOnClickListener(mStartListener); + holder.stopButton = ((Button) convertView.findViewById(R.id.stop)); + holder.stopButton.setOnClickListener(mStopListener); + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + + final String token = mTokens.get(position); + holder.tokenName.setText(mTokens.get(position)); + if (mActives.contains(token)) { + convertView.setBackgroundColor(getColor(R.color.active_color)); + } else { + convertView.setBackgroundColor(getColor(R.color.inactive_color)); + } + return convertView; + } + } + + private static class ViewHolder { + public TextView tokenName; + public Button startButton; + public Button stopButton; + } +} |