diff options
author | Takeshi Hagikura <thagikura@google.com> | 2014-12-08 00:11:34 +0900 |
---|---|---|
committer | Takeshi Hagikura <thagikura@google.com> | 2014-12-10 03:56:34 +0900 |
commit | db896235124946240d5dc9107c91b48de5493ac1 (patch) | |
tree | 58dff99c998007b76558db617b2a840f3a96eac7 /system/AppUsageStatistics | |
parent | d5beaf81a8a029741bc9701490bbca525ba65f3c (diff) | |
download | android-db896235124946240d5dc9107c91b48de5493ac1.tar.gz |
Adds AppUsageStatistics sample
Change-Id: Id16e91f8af13ab5c6da173047a09f4804ca885c5
Diffstat (limited to 'system/AppUsageStatistics')
35 files changed, 1261 insertions, 0 deletions
diff --git a/system/AppUsageStatistics/Application/.gitignore b/system/AppUsageStatistics/Application/.gitignore new file mode 100644 index 00000000..6eb878d4 --- /dev/null +++ b/system/AppUsageStatistics/Application/.gitignore @@ -0,0 +1,16 @@ +# Copyright 2013 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. +src/template/ +src/common/ +build.gradle diff --git a/system/AppUsageStatistics/Application/proguard-project.txt b/system/AppUsageStatistics/Application/proguard-project.txt new file mode 100644 index 00000000..0d8f171d --- /dev/null +++ b/system/AppUsageStatistics/Application/proguard-project.txt @@ -0,0 +1,20 @@ + To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/system/AppUsageStatistics/Application/src/main/AndroidManifest.xml b/system/AppUsageStatistics/Application/src/main/AndroidManifest.xml new file mode 100644 index 00000000..2726b4a2 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/AndroidManifest.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2014 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.appusagestatistics" + android:versionCode="1" + android:versionName="1.0"> + + <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/> + + <application android:allowBackup="true" + android:label="@string/app_name" + android:icon="@drawable/ic_launcher" + android:theme="@style/Theme.AppCompat.Light"> + + <activity android:name=".AppUsageStatisticsActivity" + android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/system/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/AppUsageStatisticsActivity.java b/system/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/AppUsageStatisticsActivity.java new file mode 100644 index 00000000..4def465f --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/AppUsageStatisticsActivity.java @@ -0,0 +1,37 @@ +/* +* Copyright 2014 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.example.android.appusagestatistics; + +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; + +/** + * Launcher Activity for the App Usage Statistics sample app. + */ +public class AppUsageStatisticsActivity extends ActionBarActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_app_usage_statistics); + if (savedInstanceState == null) { + getSupportFragmentManager().beginTransaction() + .add(R.id.container, AppUsageStatisticsFragment.newInstance()) + .commit(); + } + } +}
\ No newline at end of file diff --git a/system/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/AppUsageStatisticsFragment.java b/system/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/AppUsageStatisticsFragment.java new file mode 100644 index 00000000..50a72e77 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/AppUsageStatisticsFragment.java @@ -0,0 +1,230 @@ +/* +* Copyright 2014 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.example.android.appusagestatistics; + +import android.app.usage.UsageStats; +import android.app.usage.UsageStatsManager; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.provider.Settings; +import android.support.v4.app.Fragment; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.Spinner; +import android.widget.SpinnerAdapter; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * Fragment that demonstrates how to use App Usage Statistics API. + */ +public class AppUsageStatisticsFragment extends Fragment { + + private static final String TAG = AppUsageStatisticsFragment.class.getSimpleName(); + + //VisibleForTesting for variables below + UsageStatsManager mUsageStatsManager; + UsageListAdapter mUsageListAdapter; + RecyclerView mRecyclerView; + RecyclerView.LayoutManager mLayoutManager; + Button mOpenUsageSettingButton; + Spinner mSpinner; + + /** + * Use this factory method to create a new instance of + * this fragment using the provided parameters. + * + * @return A new instance of fragment {@link AppUsageStatisticsFragment}. + */ + public static AppUsageStatisticsFragment newInstance() { + AppUsageStatisticsFragment fragment = new AppUsageStatisticsFragment(); + return fragment; + } + + public AppUsageStatisticsFragment() { + // Required empty public constructor + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mUsageStatsManager = (UsageStatsManager) getActivity() + .getSystemService("usagestats"); //Context.USAGE_STATS_SERVICE + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_app_usage_statistics, container, false); + } + + @Override + public void onViewCreated(View rootView, Bundle savedInstanceState) { + super.onViewCreated(rootView, savedInstanceState); + + mLayoutManager = new LinearLayoutManager(getActivity()); + mUsageListAdapter = new UsageListAdapter(); + mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerview_app_usage); + mRecyclerView.setLayoutManager(mLayoutManager); + mRecyclerView.scrollToPosition(0); + mRecyclerView.setAdapter(mUsageListAdapter); + mOpenUsageSettingButton = (Button) rootView.findViewById(R.id.button_open_usage_setting); + mSpinner = (Spinner) rootView.findViewById(R.id.spinner_time_span); + SpinnerAdapter spinnerAdapter = ArrayAdapter.createFromResource(getActivity(), + R.array.action_list, android.R.layout.simple_spinner_dropdown_item); + mSpinner.setAdapter(spinnerAdapter); + mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + + String[] strings = getResources().getStringArray(R.array.action_list); + + @Override + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + StatsUsageInterval statsUsageInterval = StatsUsageInterval.getValue(strings[position]); + if (statsUsageInterval != null ) { + List<UsageStats> usageStatsList = + getUsageStatistics(statsUsageInterval.mInterval); + Collections.sort(usageStatsList, new LastTimeLaunchedComparatorDesc()); + updateAppsList(usageStatsList); + } + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + } + }); + getUsageStatistics(UsageStatsManager.INTERVAL_DAILY); + } + + /** + * Returns the {@link #mRecyclerView} sorted by the timestamp of the last time used + * including the time span specified by the intervalType argument. + * + * @param intervalType The time interval by which the stats are aggregated. + * Corresponding to the value of {@link UsageStatsManager}. + * E.g. {@link UsageStatsManager#INTERVAL_DAILY}, {@link + * UsageStatsManager#INTERVAL_WEEKLY}, + */ + public List<UsageStats> getUsageStatistics(int intervalType) { + // Get the app statistics since one year ago from the current time. + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.YEAR, -1); + + List<UsageStats> queryUsageStats = mUsageStatsManager + .queryUsageStats(intervalType, cal.getTimeInMillis(), + System.currentTimeMillis()); + + if (queryUsageStats.size() == 0) { + Log.i(TAG, "The user may not allow the access to apps usage. "); + Toast.makeText(getActivity(), + getString(R.string.explanation_access_to_appusage_is_not_enabled), + Toast.LENGTH_LONG).show(); + mOpenUsageSettingButton.setVisibility(View.VISIBLE); + mOpenUsageSettingButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)); + } + }); + } + return queryUsageStats; + } + + /** + * Updates the {@link #mRecyclerView} with the list of {@link UsageStats} passed as an argument. + * + * @param usageStatsList A list of {@link UsageStats} from which update the + * {@link #mRecyclerView}. + */ + void updateAppsList(List<UsageStats> usageStatsList) { + List<CustomUsageStats> customUsageStatsList = new ArrayList<>(); + for (int i = 0; i < usageStatsList.size(); i++) { + CustomUsageStats customUsageStats = new CustomUsageStats(); + customUsageStats.usageStats = usageStatsList.get(i); + try { + Drawable appIcon = getActivity().getPackageManager() + .getApplicationIcon(customUsageStats.usageStats.getPackageName()); + customUsageStats.appIcon = appIcon; + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, String.format("App Icon is not found for %s", + customUsageStats.usageStats.getPackageName())); + customUsageStats.appIcon = getActivity() + .getDrawable(R.drawable.ic_default_app_launcher); + } + customUsageStatsList.add(customUsageStats); + } + mUsageListAdapter.setCustomUsageStatsList(customUsageStatsList); + mUsageListAdapter.notifyDataSetChanged(); + mRecyclerView.scrollToPosition(0); + } + + /** + * The {@link Comparator} to sort a collection of {@link UsageStats} sorted by the timestamp + * last time the app was used in the descendant order. + */ + private static class LastTimeLaunchedComparatorDesc implements Comparator<UsageStats> { + + @Override + public int compare(UsageStats left, UsageStats right) { + return (int) (right.getLastTimeUsed() - left.getLastTimeUsed()); + } + } + + /** + * Enum represents the intervals for {@link android.app.usage.UsageStatsManager} so that + * values for intervals can be found by a String representation. + * + */ + //VisibleForTesting + static enum StatsUsageInterval { + DAILY("Daily", UsageStatsManager.INTERVAL_DAILY), + WEEKLY("Weekly", UsageStatsManager.INTERVAL_WEEKLY), + MONTHLY("Monthly", UsageStatsManager.INTERVAL_MONTHLY), + YEARLY("Yearly", UsageStatsManager.INTERVAL_YEARLY); + + private int mInterval; + private String mStringRepresentation; + + StatsUsageInterval(String stringRepresentation, int interval) { + mStringRepresentation = stringRepresentation; + mInterval = interval; + } + + static StatsUsageInterval getValue(String stringRepresentation) { + for (StatsUsageInterval statsUsageInterval : values()) { + if (statsUsageInterval.mStringRepresentation.equals(stringRepresentation)) { + return statsUsageInterval; + } + } + return null; + } + } +} diff --git a/system/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/CustomUsageStats.java b/system/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/CustomUsageStats.java new file mode 100644 index 00000000..b5b15c4e --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/CustomUsageStats.java @@ -0,0 +1,28 @@ +/* +* Copyright 2014 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.example.android.appusagestatistics; + +import android.app.usage.UsageStats; +import android.graphics.drawable.Drawable; + +/** + * Entity class represents usage stats and app icon. + */ +public class CustomUsageStats { + public UsageStats usageStats; + public Drawable appIcon; +} diff --git a/system/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/UsageListAdapter.java b/system/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/UsageListAdapter.java new file mode 100644 index 00000000..ab1d0376 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/UsageListAdapter.java @@ -0,0 +1,95 @@ +/* +* Copyright (C) 2014 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.example.android.appusagestatistics; + +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Provide views to RecyclerView with the directory entries. + */ +public class UsageListAdapter extends RecyclerView.Adapter<UsageListAdapter.ViewHolder> { + + private List<CustomUsageStats> mCustomUsageStatsList = new ArrayList<>(); + private DateFormat mDateFormat = new SimpleDateFormat(); + + /** + * Provide a reference to the type of views that you are using (custom ViewHolder) + */ + public static class ViewHolder extends RecyclerView.ViewHolder { + private final TextView mPackageName; + private final TextView mLastTimeUsed; + private final ImageView mAppIcon; + + public ViewHolder(View v) { + super(v); + mPackageName = (TextView) v.findViewById(R.id.textview_package_name); + mLastTimeUsed = (TextView) v.findViewById(R.id.textview_last_time_used); + mAppIcon = (ImageView) v.findViewById(R.id.app_icon); + } + + public TextView getLastTimeUsed() { + return mLastTimeUsed; + } + + public TextView getPackageName() { + return mPackageName; + } + + public ImageView getAppIcon() { + return mAppIcon; + } + } + + public UsageListAdapter() { + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { + View v = LayoutInflater.from(viewGroup.getContext()) + .inflate(R.layout.usage_row, viewGroup, false); + return new ViewHolder(v); + } + + @Override + public void onBindViewHolder(ViewHolder viewHolder, final int position) { + viewHolder.getPackageName().setText( + mCustomUsageStatsList.get(position).usageStats.getPackageName()); + long lastTimeUsed = mCustomUsageStatsList.get(position).usageStats.getLastTimeUsed(); + viewHolder.getLastTimeUsed().setText(mDateFormat.format(new Date(lastTimeUsed))); + viewHolder.getAppIcon().setImageDrawable(mCustomUsageStatsList.get(position).appIcon); + } + + @Override + public int getItemCount() { + return mCustomUsageStatsList.size(); + } + + public void setCustomUsageStatsList(List<CustomUsageStats> customUsageStats) { + mCustomUsageStatsList = customUsageStats; + } +}
\ No newline at end of file diff --git a/system/AppUsageStatistics/Application/src/main/res/drawable-hdpi/ic_default_app_launcher.png b/system/AppUsageStatistics/Application/src/main/res/drawable-hdpi/ic_default_app_launcher.png Binary files differnew file mode 100644 index 00000000..96a442e5 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/drawable-hdpi/ic_default_app_launcher.png diff --git a/system/AppUsageStatistics/Application/src/main/res/drawable-hdpi/ic_launcher.png b/system/AppUsageStatistics/Application/src/main/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100755 index 00000000..3cf5e8b4 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/system/AppUsageStatistics/Application/src/main/res/drawable-mdpi/ic_default_app_launcher.png b/system/AppUsageStatistics/Application/src/main/res/drawable-mdpi/ic_default_app_launcher.png Binary files differnew file mode 100644 index 00000000..359047df --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/drawable-mdpi/ic_default_app_launcher.png diff --git a/system/AppUsageStatistics/Application/src/main/res/drawable-mdpi/ic_launcher.png b/system/AppUsageStatistics/Application/src/main/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100755 index 00000000..51553c5d --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/system/AppUsageStatistics/Application/src/main/res/drawable-xhdpi/ic_default_app_launcher.png b/system/AppUsageStatistics/Application/src/main/res/drawable-xhdpi/ic_default_app_launcher.png Binary files differnew file mode 100644 index 00000000..71c6d760 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/drawable-xhdpi/ic_default_app_launcher.png diff --git a/system/AppUsageStatistics/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/system/AppUsageStatistics/Application/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100755 index 00000000..52480002 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/system/AppUsageStatistics/Application/src/main/res/drawable-xxhdpi/ic_default_app_launcher.png b/system/AppUsageStatistics/Application/src/main/res/drawable-xxhdpi/ic_default_app_launcher.png Binary files differnew file mode 100644 index 00000000..4df18946 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/drawable-xxhdpi/ic_default_app_launcher.png diff --git a/system/AppUsageStatistics/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/system/AppUsageStatistics/Application/src/main/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100755 index 00000000..7f162009 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/system/AppUsageStatistics/Application/src/main/res/layout/activity_app_usage_statistics.xml b/system/AppUsageStatistics/Application/src/main/res/layout/activity_app_usage_statistics.xml new file mode 100644 index 00000000..2627c8b7 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/layout/activity_app_usage_statistics.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2014 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. +--> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/container" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context="com.example.android.appusagestatistics.AppUsageStatisticsActivity" + tools:ignore="MergeRootFrame" /> diff --git a/system/AppUsageStatistics/Application/src/main/res/layout/fragment_app_usage_statistics.xml b/system/AppUsageStatistics/Application/src/main/res/layout/fragment_app_usage_statistics.xml new file mode 100644 index 00000000..1d567b76 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/layout/fragment_app_usage_statistics.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2014 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:gravity="center_vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:padding="@dimen/margin_medium"> + + <Button android:id="@+id/button_open_usage_setting" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/open_app_usage_setting" + android:visibility="gone" + /> + + <LinearLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + > + <TextView android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/time_span" + /> + + <Spinner android:id="@+id/spinner_time_span" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + </LinearLayout> + + <android.support.v7.widget.RecyclerView + android:id="@+id/recyclerview_app_usage" + android:layout_marginLeft="@dimen/margin_small" + android:layout_marginRight="@dimen/margin_small" + android:scrollbars="vertical" + android:drawSelectorOnTop="true" + android:layout_width="match_parent" + android:layout_height="match_parent"/> + +</LinearLayout> diff --git a/system/AppUsageStatistics/Application/src/main/res/layout/usage_row.xml b/system/AppUsageStatistics/Application/src/main/res/layout/usage_row.xml new file mode 100644 index 00000000..c16f039e --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/layout/usage_row.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2014 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. +--> + +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="@dimen/usage_row_height" + > + + <LinearLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_centerVertical="true" + android:gravity="center_vertical" + > + <ImageView android:id="@+id/app_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + /> + <LinearLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/margin_medium" + android:orientation="vertical" + > + + <TextView + android:id="@+id/textview_package_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/PackageNameFont" + /> + + <LinearLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + > + + <TextView + android:id="@+id/textview_last_time_used_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/last_time_used" + /> + + <TextView + android:id="@+id/textview_last_time_used" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + /> + </LinearLayout> + </LinearLayout> + </LinearLayout> + + <View android:id="@+id/divider" + android:layout_width="match_parent" + android:layout_height="1dp" + android:background="#bbbbbb"/> + +</RelativeLayout>
\ No newline at end of file diff --git a/system/AppUsageStatistics/Application/src/main/res/values/dimens.xml b/system/AppUsageStatistics/Application/src/main/res/values/dimens.xml new file mode 100644 index 00000000..d1741c33 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/values/dimens.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2014 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> + <dimen name="usage_row_height">72dp</dimen> +</resources>
\ No newline at end of file diff --git a/system/AppUsageStatistics/Application/src/main/res/values/navigation_items.xml b/system/AppUsageStatistics/Application/src/main/res/values/navigation_items.xml new file mode 100644 index 00000000..b36a4a58 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/values/navigation_items.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2014 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> + <string-array name="action_list"> + <item>Daily</item> + <item>Weekly</item> + <item>Monthly</item> + <item>Yearly</item> + </string-array> +</resources>
\ No newline at end of file diff --git a/system/AppUsageStatistics/Application/src/main/res/values/strings.xml b/system/AppUsageStatistics/Application/src/main/res/values/strings.xml new file mode 100644 index 00000000..2caaf900 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/values/strings.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2014 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> + <string name="open_app_usage_setting">Open Apps with usage access settings</string> + <string name="last_time_used">"Last time used: "</string> + <string name="time_span">"Time span: "</string> + <string name="explanation_access_to_appusage_is_not_enabled">Failed to retrieve app usage + statistics. You may need to enable access " + + "for this app through Settings > Security > Apps with usage access + </string> +</resources> diff --git a/system/AppUsageStatistics/Application/src/main/res/values/styles.xml b/system/AppUsageStatistics/Application/src/main/res/values/styles.xml new file mode 100644 index 00000000..d4002764 --- /dev/null +++ b/system/AppUsageStatistics/Application/src/main/res/values/styles.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2014 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="PackageNameFont" parent="@android:style/TextAppearance.Small"> + <item name="android:textColor">#000000</item> + </style> +</resources>
\ No newline at end of file diff --git a/system/AppUsageStatistics/Application/tests/src/com/example/android/appusagestatistics/AppUsageStatisticsActivityTests.java b/system/AppUsageStatistics/Application/tests/src/com/example/android/appusagestatistics/AppUsageStatisticsActivityTests.java new file mode 100644 index 00000000..f2e3ea91 --- /dev/null +++ b/system/AppUsageStatistics/Application/tests/src/com/example/android/appusagestatistics/AppUsageStatisticsActivityTests.java @@ -0,0 +1,70 @@ +/* +* Copyright 2014 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. +*/ +/* +* Copyright (C) 2014 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.example.android.appusagestatistics; + +import android.test.ActivityInstrumentationTestCase2; + +/** + * Tests for {@link AppUsageStatisticsActivity}. + */ +public class AppUsageStatisticsActivityTests + extends ActivityInstrumentationTestCase2<AppUsageStatisticsActivity> { + + private AppUsageStatisticsActivity mTestActivity; + private AppUsageStatisticsFragment mTestFragment; + + public AppUsageStatisticsActivityTests() { + super(AppUsageStatisticsActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + // Starts the activity under test using the default Intent with: + // action = {@link Intent#ACTION_MAIN} + // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK} + // All other fields are null or empty. + mTestActivity = getActivity(); + mTestFragment = (AppUsageStatisticsFragment) + mTestActivity.getSupportFragmentManager().getFragments().get(0); + } + + /** + * Test if the test fixture has been set up correctly. + */ + public void testPreconditions() { + //Try to add a message to add context to your assertions. These messages will be shown if + //a tests fails and make it easy to understand why a test failed + assertNotNull("mTestActivity is null", mTestActivity); + assertNotNull("mTestFragment is null", mTestFragment); + } +} diff --git a/system/AppUsageStatistics/Application/tests/src/com/example/android/appusagestatistics/AppUsageStatisticsFragmentTests.java b/system/AppUsageStatistics/Application/tests/src/com/example/android/appusagestatistics/AppUsageStatisticsFragmentTests.java new file mode 100644 index 00000000..d8adb1ce --- /dev/null +++ b/system/AppUsageStatistics/Application/tests/src/com/example/android/appusagestatistics/AppUsageStatisticsFragmentTests.java @@ -0,0 +1,97 @@ +/* +* Copyright 2014 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.example.android.appusagestatistics; + +import com.example.android.appusagestatistics.AppUsageStatisticsFragment.StatsUsageInterval; + +import android.app.usage.UsageStats; +import android.app.usage.UsageStatsManager; +import android.test.ActivityInstrumentationTestCase2; + +import java.util.List; + +/** + * Tests for {@link com.example.android.appusagestatistics.AppUsageStatisticsFragment}. + */ +public class AppUsageStatisticsFragmentTests + extends ActivityInstrumentationTestCase2<AppUsageStatisticsActivity> { + + private AppUsageStatisticsActivity mTestActivity; + private AppUsageStatisticsFragment mTestFragment; + + public AppUsageStatisticsFragmentTests() { + super(AppUsageStatisticsActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + // Starts the activity under test using the default Intent with: + // action = {@link Intent#ACTION_MAIN} + // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK} + // All other fields are null or empty. + mTestActivity = getActivity(); + mTestFragment = (AppUsageStatisticsFragment) + mTestActivity.getSupportFragmentManager().getFragments().get(0); + } + + /** + * Test if the test fixture has been set up correctly. + */ + public void testPreconditions() { + assertNotNull(mTestFragment.mUsageStatsManager); + assertNotNull(mTestFragment.mUsageListAdapter); + assertNotNull(mTestFragment.mRecyclerView); + assertNotNull(mTestFragment.mLayoutManager); + assertNotNull(mTestFragment.mOpenUsageSettingButton); + assertNotNull(mTestFragment.mSpinner); + } + + public void testStatsUsageInterval_getValue() { + assertTrue(StatsUsageInterval.DAILY == StatsUsageInterval.getValue("Daily")); + assertTrue(StatsUsageInterval.WEEKLY == StatsUsageInterval.getValue("Weekly")); + assertTrue(StatsUsageInterval.MONTHLY == StatsUsageInterval.getValue("Monthly")); + assertTrue(StatsUsageInterval.YEARLY == StatsUsageInterval.getValue("Yearly")); + assertNull(StatsUsageInterval.getValue("NonExistent")); + } + + public void testGetUsageStatistics() { + List<UsageStats> usageStatsList = mTestFragment + .getUsageStatistics(UsageStatsManager.INTERVAL_DAILY); + + // Whether the usageStatsList has any UsageStats depends on if the app is granted + // the access to App usage statistics. + // Only check non null here. + assertNotNull(usageStatsList); + } + + public void testUpdateAppsList() { + List<UsageStats> usageStatsList = mTestFragment + .getUsageStatistics(UsageStatsManager.INTERVAL_DAILY); + + mTestFragment.updateAppsList(usageStatsList); + getInstrumentation().waitForIdleSync(); + + // The result depends on if the app is granted the access to App usage statistics. + if (usageStatsList.size() == 0) { + assertTrue(mTestFragment.mUsageListAdapter.getItemCount() == 0); + } else { + assertTrue(mTestFragment.mUsageListAdapter.getItemCount() > 0); + } + } +} diff --git a/system/AppUsageStatistics/build.gradle b/system/AppUsageStatistics/build.gradle new file mode 100644 index 00000000..2b8d1ef1 --- /dev/null +++ b/system/AppUsageStatistics/build.gradle @@ -0,0 +1,11 @@ + +// BEGIN_EXCLUDE +import com.example.android.samples.build.SampleGenPlugin +apply plugin: SampleGenPlugin + +samplegen { + pathToBuild "../../../../build" + pathToSamplesCommon "../../common" +} +apply from: "../../../../build/build.gradle" +// END_EXCLUDE diff --git a/system/AppUsageStatistics/buildSrc/build.gradle b/system/AppUsageStatistics/buildSrc/build.gradle new file mode 100644 index 00000000..8c294c23 --- /dev/null +++ b/system/AppUsageStatistics/buildSrc/build.gradle @@ -0,0 +1,15 @@ +repositories { + mavenCentral() +} +dependencies { + compile 'org.freemarker:freemarker:2.3.20' +} + +sourceSets { + main { + groovy { + srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy") + } + } +} + diff --git a/system/AppUsageStatistics/gradle/wrapper/gradle-wrapper.jar b/system/AppUsageStatistics/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 00000000..8c0fb64a --- /dev/null +++ b/system/AppUsageStatistics/gradle/wrapper/gradle-wrapper.jar diff --git a/system/AppUsageStatistics/gradle/wrapper/gradle-wrapper.properties b/system/AppUsageStatistics/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..8a27ebfa --- /dev/null +++ b/system/AppUsageStatistics/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sun Dec 07 22:52:45 JST 2014 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip diff --git a/system/AppUsageStatistics/gradlew b/system/AppUsageStatistics/gradlew new file mode 100755 index 00000000..91a7e269 --- /dev/null +++ b/system/AppUsageStatistics/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/system/AppUsageStatistics/gradlew.bat b/system/AppUsageStatistics/gradlew.bat new file mode 100644 index 00000000..aec99730 --- /dev/null +++ b/system/AppUsageStatistics/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/system/AppUsageStatistics/screenshots/screenshot-1.png b/system/AppUsageStatistics/screenshots/screenshot-1.png Binary files differnew file mode 100644 index 00000000..ab0da864 --- /dev/null +++ b/system/AppUsageStatistics/screenshots/screenshot-1.png diff --git a/system/AppUsageStatistics/screenshots/screenshot-2.png b/system/AppUsageStatistics/screenshots/screenshot-2.png Binary files differnew file mode 100644 index 00000000..7663ebdf --- /dev/null +++ b/system/AppUsageStatistics/screenshots/screenshot-2.png diff --git a/system/AppUsageStatistics/screenshots/web-icon.png b/system/AppUsageStatistics/screenshots/web-icon.png Binary files differnew file mode 100755 index 00000000..68af9d0e --- /dev/null +++ b/system/AppUsageStatistics/screenshots/web-icon.png diff --git a/system/AppUsageStatistics/settings.gradle b/system/AppUsageStatistics/settings.gradle new file mode 100644 index 00000000..9464a359 --- /dev/null +++ b/system/AppUsageStatistics/settings.gradle @@ -0,0 +1 @@ +include 'Application' diff --git a/system/AppUsageStatistics/template-params.xml b/system/AppUsageStatistics/template-params.xml new file mode 100644 index 00000000..38f5781d --- /dev/null +++ b/system/AppUsageStatistics/template-params.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2014 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. +--> +<sample> + <name>AppUsageStatistics</name> + <group>System</group> + <package>com.example.android.appusagestatistics</package> + + <minSdk>21</minSdk> + + <dependency>com.android.support:recyclerview-v7:+</dependency> + <dependency>com.android.support:appcompat-v7:21.+</dependency> + + <strings> + <intro> + <![CDATA[ + This sample explains how to use App usage statistics API, which was introduced + in Android 5.0. + ]]> + </intro> + </strings> + + <template src="base" /> + + <metadata> + <status>DRAFT</status> + <categories>System</categories> + <technologies>Android</technologies> + <languages>Java</languages> + <solutions>Mobile</solutions> + <level>INTERMEDIATE</level> + <icon>screenshots/web-icon.png</icon> + <screenshots> + <img>screenshots/screenshot-1.png</img> + <img>screenshots/screenshot-2.png</img> + </screenshots> + <api_refs> + <android>android.app.usage.UsageStats</android> + <android>android.app.usage.UsageStatsManager</android> + </api_refs> + + <description> +<![CDATA[ +A basic app showing how to use App usage statistics API to let users collect statistics related +to usage of the applications. +]]> + </description> + + <intro> +<![CDATA[ +The [App usage statistics][1] API allows app developers to collect statistics related to usage of +the applications. This API provides more detailed usage information than the deprecated +[getRecentTasks()][2] method. + +This example illustrates how to use the App usage statistics API by showing the applications sorted +by the timestamp of the last time each app was used. + +To use this API, you must first declare the `android.permission.PACKAGE_USAGE_STATS` permission +in your manifest. The user must also enable access for this app through +`Settings > Security > Apps with usage access`. + +To collect the statistics of the app usage, you need to first get the instance of +[UsageStatsManager][3] by the following code: + +```java +mUsageStatsManager = (UsageStatsManager) getActivity() + .getSystemService(Context.USAGE_STATS_SERVICE); +``` + +Then you can retrieve the statistics of the app usage by the following method: + +```java +Calendar cal = Calendar.getInstance(); +cal.add(Calendar.YEAR, -1); +List<UsageStats> queryUsageStats = mUsageStatsManager + .queryUsageStats(UsageStatsManager.INTERVAL_DAILY, cal.getTimeInMillis(), + System.currentTimeMillis()); +``` + +The first argument of the [queryUsageStats()][4] is used for the time interval by which the +stats are aggregated. The second and the third arguments are used for specifying the beginning +and the end of the range of the stats to include in the results. + +[1]: https://developer.android.com/reference/android/app/usage/package-summary.html +[2]: https://developer.android.com/reference/android/app/ActivityManager.html#getRecentTasks(int%2C%20int) +[3]: https://developer.android.com/reference/android/app/usage/UsageStatsManager.html +[4]: https://developer.android.com/reference/android/app/usage/UsageStatsManager.html#queryUsageStats(int%2C%20long%2C%20long) +]]> + </intro> + </metadata> +</sample> |