diff options
author | Trevor Johns <trevorjohns@google.com> | 2014-12-11 14:22:56 -0800 |
---|---|---|
committer | Trevor Johns <trevorjohns@google.com> | 2014-12-11 15:30:20 -0800 |
commit | f4852427259f175605844f385f0be2eb2ae0e5ec (patch) | |
tree | 8b5f06594a3c6de514c475786347ecbcd318d905 /prebuilts/gradle | |
parent | 5073d44d2b933234d20338d1daaabbc3e9c60d65 (diff) | |
download | build-f4852427259f175605844f385f0be2eb2ae0e5ec.tar.gz |
Sync sample prebuilts for lmp-docs
Synced to developers/samples/android commit
c90e4cf627af4eb1c42b759a54baf3ab07998e27.
Change-Id: I12bdf2049bd0c735a2385374ed13862b105247f6
Diffstat (limited to 'prebuilts/gradle')
345 files changed, 10309 insertions, 464 deletions
diff --git a/prebuilts/gradle/ActionBarCompat-Basic/Application/build.gradle b/prebuilts/gradle/ActionBarCompat-Basic/Application/build.gradle index 1eb334ab..39b494bc 100644 --- a/prebuilts/gradle/ActionBarCompat-Basic/Application/build.gradle +++ b/prebuilts/gradle/ActionBarCompat-Basic/Application/build.gradle @@ -17,11 +17,11 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" - compile "com.android.support:appcompat-v7:18.0.+" + compile "com.android.support:appcompat-v7:21.0.2" } // The sample build uses multiple directories to diff --git a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/.google/packaging.yaml b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/.google/packaging.yaml index f30211c3..a799cfd4 100644 --- a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/.google/packaging.yaml +++ b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/.google/packaging.yaml @@ -9,4 +9,8 @@ categories: [UI] languages: [Java] solutions: [Mobile] github: android-ActionBarCompat-ListPopupMenu +level: INTERMEDIATE +icon: screenshots/icon-web.png +apiRefs: + - android:android.support.v7.widget.PopupMenu license: apache2 diff --git a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/Application/build.gradle b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/Application/build.gradle index af12607c..39b494bc 100644 --- a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/Application/build.gradle +++ b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/Application/build.gradle @@ -17,11 +17,11 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" - compile "com.android.support:appcompat-v7:+" + compile "com.android.support:appcompat-v7:21.0.2" } // The sample build uses multiple directories to diff --git a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/README.md b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/README.md index 282ed60a..5a366eb8 100644 --- a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/README.md +++ b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/README.md @@ -1,8 +1,17 @@ Android ActionBarCompat-ListPopupMenu Sample =================================== -This sample shows you how to use {@link android.support.v7.widget.PopupMenu PopupMenu} -from ActionBarCompat to create a list, with each item having a dropdown menu. +This sample shows how to display a pop up menu using PopupMenu from the v7 appcompat library. + +Introduction +------------ + +This sample displays a list of items and for each item, an icon can be clicked. When it is clicked, a pop up menu is shown, placed below the item, using the [PopupMenu][1] from the v7 appcompat support library. + +The sample uses [ListFragment][2] from the v4 support library to display the list. It shows how to instantiate and display the [PopupMenu][1], as well as how to use `setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener())` to process the user actions on the [PopupMenu][1]. + +[1]: https://developer.android.com/reference/android/support/v7/widget/PopupMenu.html +[2]: https://developer.android.com/reference/android/support/v4/app/ListFragment.html Pre-requisites -------------- @@ -11,6 +20,11 @@ Pre-requisites - Android Build Tools v21.1.1 - Android Support Repository +Screenshots +------------- + +<img src="screenshots/1-main.png" height="400" alt="Screenshot"/> <img src="screenshots/2-popup.png" height="400" alt="Screenshot"/> + Getting Started --------------- diff --git a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/screenshots/1-main.png b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/screenshots/1-main.png Binary files differnew file mode 100644 index 00000000..f69ed96f --- /dev/null +++ b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/screenshots/1-main.png diff --git a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/screenshots/2-popup.png b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/screenshots/2-popup.png Binary files differnew file mode 100644 index 00000000..b03862d1 --- /dev/null +++ b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/screenshots/2-popup.png diff --git a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/screenshots/icon-web.png b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/screenshots/icon-web.png Binary files differnew file mode 100644 index 00000000..5220b83f --- /dev/null +++ b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/screenshots/icon-web.png diff --git a/prebuilts/gradle/ActionBarCompat-ShareActionProvider/Application/build.gradle b/prebuilts/gradle/ActionBarCompat-ShareActionProvider/Application/build.gradle index 1eb334ab..39b494bc 100644 --- a/prebuilts/gradle/ActionBarCompat-ShareActionProvider/Application/build.gradle +++ b/prebuilts/gradle/ActionBarCompat-ShareActionProvider/Application/build.gradle @@ -17,11 +17,11 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" - compile "com.android.support:appcompat-v7:18.0.+" + compile "com.android.support:appcompat-v7:21.0.2" } // The sample build uses multiple directories to diff --git a/prebuilts/gradle/ActionBarCompat-Styled/Application/build.gradle b/prebuilts/gradle/ActionBarCompat-Styled/Application/build.gradle index 1eb334ab..8a24c4d1 100644 --- a/prebuilts/gradle/ActionBarCompat-Styled/Application/build.gradle +++ b/prebuilts/gradle/ActionBarCompat-Styled/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" compile "com.android.support:appcompat-v7:18.0.+" } diff --git a/prebuilts/gradle/ActivityInstrumentation/Application/build.gradle b/prebuilts/gradle/ActivityInstrumentation/Application/build.gradle index 05020be5..76169dee 100644 --- a/prebuilts/gradle/ActivityInstrumentation/Application/build.gradle +++ b/prebuilts/gradle/ActivityInstrumentation/Application/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" + compile "com.android.support:support-v4:21.0.2" } diff --git a/prebuilts/gradle/ActivitySceneTransitionBasic/Application/build.gradle b/prebuilts/gradle/ActivitySceneTransitionBasic/Application/build.gradle index 28005541..c2ac02c4 100644 --- a/prebuilts/gradle/ActivitySceneTransitionBasic/Application/build.gradle +++ b/prebuilts/gradle/ActivitySceneTransitionBasic/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" compile "com.squareup.picasso:picasso:2.4.0" } diff --git a/prebuilts/gradle/AdapterTransition/Application/build.gradle b/prebuilts/gradle/AdapterTransition/Application/build.gradle index bfed04fa..c6b8c26a 100644 --- a/prebuilts/gradle/AdapterTransition/Application/build.gradle +++ b/prebuilts/gradle/AdapterTransition/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/AdvancedImmersiveMode/Application/build.gradle b/prebuilts/gradle/AdvancedImmersiveMode/Application/build.gradle index 05020be5..76169dee 100644 --- a/prebuilts/gradle/AdvancedImmersiveMode/Application/build.gradle +++ b/prebuilts/gradle/AdvancedImmersiveMode/Application/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" + compile "com.android.support:support-v4:21.0.2" } diff --git a/prebuilts/gradle/AgendaData/.google/packaging.yaml b/prebuilts/gradle/AgendaData/.google/packaging.yaml index 5b9e7913..0186ce1c 100644 --- a/prebuilts/gradle/AgendaData/.google/packaging.yaml +++ b/prebuilts/gradle/AgendaData/.google/packaging.yaml @@ -9,4 +9,10 @@ categories: [Wearable] languages: [Java] solutions: [Mobile] github: android-AgendaData +level: INTERMEDIATE +icon: Wearable/src/main/res/drawable-xxhdpi/ic_launcher.png +apiRefs: + - android:android.app.IntentService + - com.google.android.gms.wearable.DataApi + - com.google.android.gms.wearable.Node license: apache2 diff --git a/prebuilts/gradle/AgendaData/README.md b/prebuilts/gradle/AgendaData/README.md index 52ff0197..c1dcff10 100644 --- a/prebuilts/gradle/AgendaData/README.md +++ b/prebuilts/gradle/AgendaData/README.md @@ -1,11 +1,22 @@ Android AgendaData Sample =================================== -Syncs calendar events to your wearable at the press of a button, using the Wearable -DataApi to transmit data such as event time, description, and background image. The DataItems can be -deleted individually via an action on the event notifications, or all at once via a button on the -companion. When deleted using the notification action, a ConfirmationActivity is used to indicate -success or failure. +Sample demonstrating sync of calendar events to a wearable by the press of a button. + +Introduction +------------ + +Using the Wearable [DataApi][1] allows to transmit data such as event time, +description, and background image. + +The sent [DataItems][2] can be deleted individually via an action on the event notifications, +or all at once via a button on the companion. + +When deleted using the notification action, a ConfirmationActivity is used to indicate +success or failure. The sample shows implementations for both the success as well failure case. + +[1]: https://developer.android.com/reference/com/google/android/gms/wearable/DataApi.html +[2]: https://developer.android.com/reference/com/google/android/gms/wearable/DataItem.html Pre-requisites -------------- @@ -14,6 +25,11 @@ Pre-requisites - Android Build Tools v21.1.1 - Android Support Repository +Screenshots +------------- + +<img src="screenshots/companion_agenda_data.png" height="400" alt="Screenshot"/> <img src="screenshots/dummy_calendar_event.png" height="400" alt="Screenshot"/> + Getting Started --------------- diff --git a/prebuilts/gradle/AppRestrictionEnforcer/Application/build.gradle b/prebuilts/gradle/AppRestrictionEnforcer/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/AppRestrictionEnforcer/Application/build.gradle +++ b/prebuilts/gradle/AppRestrictionEnforcer/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/AppRestrictionEnforcerFragment.java b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/AppRestrictionEnforcerFragment.java index 6db54f65..8b0620fb 100644 --- a/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/AppRestrictionEnforcerFragment.java +++ b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/AppRestrictionEnforcerFragment.java @@ -22,34 +22,34 @@ import android.content.Context; import android.content.RestrictionEntry; import android.content.RestrictionsManager; import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.Spinner; import android.widget.Switch; -import android.widget.TextView; import android.widget.Toast; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** * This fragment provides UI and functionality to set restrictions on the AppRestrictionSchema * sample. */ -public class AppRestrictionEnforcerFragment extends Fragment implements View.OnClickListener, - CompoundButton.OnCheckedChangeListener { - - /** - * Package name of the AppRestrictionSchema sample. - */ - private static final String PACKAGE_NAME_APP_RESTRICTION_SCHEMA - = "com.example.android.apprestrictionschema"; +public class AppRestrictionEnforcerFragment extends Fragment implements + CompoundButton.OnCheckedChangeListener, AdapterView.OnItemSelectedListener { /** * Key for {@link SharedPreferences} @@ -62,15 +62,38 @@ public class AppRestrictionEnforcerFragment extends Fragment implements View.OnC private static final String RESTRICTION_KEY_SAY_HELLO = "can_say_hello"; /** - * Default boolean value for "can_say_hello" restriction. The actual value is loaded in - * {@link #loadRestrictions(android.app.Activity)}. + * Key for the string restriction in AppRestrictionSchema. + */ + private static final String RESTRICTION_KEY_MESSAGE = "message"; + + /** + * Key for the integer restriction in AppRestrictionSchema. + */ + private static final String RESTRICTION_KEY_NUMBER = "number"; + + /** + * Key for the choice restriction in AppRestrictionSchema. + */ + private static final String RESTRICTION_KEY_RANK = "rank"; + + /** + * Key for the multi-select restriction in AppRestrictionSchema. */ - private boolean mDefaultValueRestrictionSayHello; + private static final String RESTRICTION_KEY_APPROVALS = "approvals"; + + private static final String DELIMETER = ","; + + /** + * Current status of the restrictions. + */ + private Bundle mCurrentRestrictions = new Bundle(); // UI Components - private TextView mTextStatus; - private Button mButtonUnhide; private Switch mSwitchSayHello; + private EditText mEditMessage; + private EditText mEditNumber; + private Spinner mSpinnerRank; + private LinearLayout mLayoutApprovals; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @@ -80,152 +103,262 @@ public class AppRestrictionEnforcerFragment extends Fragment implements View.OnC @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - mTextStatus = (TextView) view.findViewById(R.id.status); - mButtonUnhide = (Button) view.findViewById(R.id.unhide); + // Retain references for the UI elements mSwitchSayHello = (Switch) view.findViewById(R.id.say_hello); - mButtonUnhide.setOnClickListener(this); - mSwitchSayHello.setOnCheckedChangeListener(this); + mEditMessage = (EditText) view.findViewById(R.id.message); + mEditNumber = (EditText) view.findViewById(R.id.number); + mSpinnerRank = (Spinner) view.findViewById(R.id.rank); + mLayoutApprovals = (LinearLayout) view.findViewById(R.id.approvals); } @Override public void onResume() { super.onResume(); - updateUi(getActivity()); + loadRestrictions(getActivity()); } @Override - public void onClick(View view) { - switch (view.getId()) { - case R.id.unhide: { - unhideApp(getActivity()); + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + switch (compoundButton.getId()) { + case R.id.say_hello: { + saveCanSayHello(getActivity(), checked); + break; + } + case R.id.approval: { + if (checked) { + addApproval(getActivity(), (String) compoundButton.getTag()); + } else { + removeApproval(getActivity(), (String) compoundButton.getTag()); + } break; } } } + private TextWatcher mWatcherMessage = new EasyTextWatcher() { + @Override + public void afterTextChanged(Editable s) { + saveMessage(getActivity(), s.toString()); + } + }; + + private TextWatcher mWatcherNumber = new EasyTextWatcher() { + @Override + public void afterTextChanged(Editable s) { + try { + String string = s.toString(); + if (!TextUtils.isEmpty(string)) { + saveNumber(getActivity(), Integer.parseInt(string)); + } + } catch (NumberFormatException e) { + Toast.makeText(getActivity(), "Not an integer!", Toast.LENGTH_SHORT).show(); + } + } + }; + @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { - switch (compoundButton.getId()) { - case R.id.say_hello: { - allowSayHello(getActivity(), checked); + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + switch (parent.getId()) { + case R.id.rank: { + saveRank(getActivity(), (String) parent.getAdapter().getItem(position)); break; } } } + @Override + public void onNothingSelected(AdapterView<?> parent) { + // Nothing to do + } + /** - * Updates the UI components according to the current status of AppRestrictionSchema and its - * restriction. + * Loads the restrictions for the AppRestrictionSchema sample. In this implementation, we just + * read the default value for the "can_say_hello" restriction. * * @param activity The activity */ - private void updateUi(Activity activity) { - PackageManager packageManager = activity.getPackageManager(); - try { - ApplicationInfo info = packageManager.getApplicationInfo( - PACKAGE_NAME_APP_RESTRICTION_SCHEMA, PackageManager.GET_UNINSTALLED_PACKAGES); - DevicePolicyManager devicePolicyManager = - (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE); - if (0 < (info.flags & ApplicationInfo.FLAG_INSTALLED)) { - if (!devicePolicyManager.isApplicationHidden( - EnforcerDeviceAdminReceiver.getComponentName(activity), - PACKAGE_NAME_APP_RESTRICTION_SCHEMA)) { - // The app is ready - loadRestrictions(activity); - mTextStatus.setVisibility(View.GONE); - mButtonUnhide.setVisibility(View.GONE); - mSwitchSayHello.setVisibility(View.VISIBLE); - mSwitchSayHello.setOnCheckedChangeListener(null); - mSwitchSayHello.setChecked(canSayHello(activity)); - mSwitchSayHello.setOnCheckedChangeListener(this); - } else { - // The app is installed but hidden in this profile - mTextStatus.setText(R.string.status_not_activated); - mTextStatus.setVisibility(View.VISIBLE); - mButtonUnhide.setVisibility(View.VISIBLE); - mSwitchSayHello.setVisibility(View.GONE); - } - } else { - // Need to reinstall the sample app - mTextStatus.setText(R.string.status_need_reinstall); - mTextStatus.setVisibility(View.VISIBLE); - mButtonUnhide.setVisibility(View.GONE); - mSwitchSayHello.setVisibility(View.GONE); + private void loadRestrictions(Activity activity) { + RestrictionsManager manager = + (RestrictionsManager) activity.getSystemService(Context.RESTRICTIONS_SERVICE); + List<RestrictionEntry> restrictions = + manager.getManifestRestrictions(Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA); + SharedPreferences prefs = activity.getSharedPreferences(PREFS_KEY, Context.MODE_PRIVATE); + for (RestrictionEntry restriction : restrictions) { + String key = restriction.getKey(); + if (RESTRICTION_KEY_SAY_HELLO.equals(key)) { + updateCanSayHello(prefs.getBoolean(RESTRICTION_KEY_SAY_HELLO, + restriction.getSelectedState())); + } else if (RESTRICTION_KEY_MESSAGE.equals(key)) { + updateMessage(prefs.getString(RESTRICTION_KEY_MESSAGE, + restriction.getSelectedString())); + } else if (RESTRICTION_KEY_NUMBER.equals(key)) { + updateNumber(prefs.getInt(RESTRICTION_KEY_NUMBER, + restriction.getIntValue())); + } else if (RESTRICTION_KEY_RANK.equals(key)) { + updateRank(activity, restriction.getChoiceValues(), + prefs.getString(RESTRICTION_KEY_RANK, restriction.getSelectedString())); + } else if (RESTRICTION_KEY_APPROVALS.equals(key)) { + updateApprovals(activity, restriction.getChoiceValues(), + TextUtils.split(prefs.getString(RESTRICTION_KEY_APPROVALS, + TextUtils.join(DELIMETER, + restriction.getAllSelectedStrings())), + DELIMETER)); } - } catch (PackageManager.NameNotFoundException e) { - mTextStatus.setText(R.string.status_not_installed); - mTextStatus.setVisibility(View.VISIBLE); - mButtonUnhide.setVisibility(View.GONE); - mSwitchSayHello.setVisibility(View.GONE); + } + } + + private void updateCanSayHello(boolean canSayHello) { + mCurrentRestrictions.putBoolean(RESTRICTION_KEY_SAY_HELLO, canSayHello); + mSwitchSayHello.setOnCheckedChangeListener(null); + mSwitchSayHello.setChecked(canSayHello); + mSwitchSayHello.setOnCheckedChangeListener(this); + } + + private void updateMessage(String message) { + mCurrentRestrictions.putString(RESTRICTION_KEY_MESSAGE, message); + mEditMessage.removeTextChangedListener(mWatcherMessage); + mEditMessage.setText(message); + mEditMessage.addTextChangedListener(mWatcherMessage); + } + + private void updateNumber(int number) { + mCurrentRestrictions.putInt(RESTRICTION_KEY_NUMBER, number); + mEditNumber.removeTextChangedListener(mWatcherNumber); + mEditNumber.setText(String.valueOf(number)); + mEditNumber.addTextChangedListener(mWatcherNumber); + } + + private void updateRank(Context context, String[] ranks, String selectedRank) { + mCurrentRestrictions.putString(RESTRICTION_KEY_RANK, selectedRank); + mSpinnerRank.setAdapter(new ArrayAdapter<>(context, + android.R.layout.simple_spinner_dropdown_item, ranks)); + mSpinnerRank.setSelection(search(ranks, selectedRank)); + mSpinnerRank.setOnItemSelectedListener(this); + } + + private void updateApprovals(Context context, String[] approvals, + String[] selectedApprovals) { + mCurrentRestrictions.putStringArray(RESTRICTION_KEY_APPROVALS, selectedApprovals); + mLayoutApprovals.removeAllViews(); + for (String approval : approvals) { + Switch sw = new Switch(context); + sw.setText(approval); + sw.setTag(approval); + sw.setChecked(Arrays.asList(selectedApprovals).contains(approval)); + sw.setOnCheckedChangeListener(this); + sw.setId(R.id.approval); + mLayoutApprovals.addView(sw); } } /** - * Unhides the AppRestrictionSchema sample in case it is hidden in this profile. + * Saves the value for the "cay_say_hello" restriction of AppRestrictionSchema. * * @param activity The activity + * @param allow The value to be set for the restriction. */ - private void unhideApp(Activity activity) { - DevicePolicyManager devicePolicyManager = - (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE); - devicePolicyManager.setApplicationHidden( - EnforcerDeviceAdminReceiver.getComponentName(activity), - PACKAGE_NAME_APP_RESTRICTION_SCHEMA, false); - Toast.makeText(activity, "Enabled the app", Toast.LENGTH_SHORT).show(); - updateUi(activity); + private void saveCanSayHello(Activity activity, boolean allow) { + mCurrentRestrictions.putBoolean(RESTRICTION_KEY_SAY_HELLO, allow); + saveRestrictions(activity); + // Note that the owner app needs to remember the restrictions on its own. + editPreferences(activity).putBoolean(RESTRICTION_KEY_SAY_HELLO, allow).apply(); } /** - * Loads the restrictions for the AppRestrictionSchema sample. In this implementation, we just - * read the default value for the "can_say_hello" restriction. + * Saves the value for the "message" restriction of AppRestrictionSchema. * * @param activity The activity + * @param message The value to be set for the restriction. */ - private void loadRestrictions(Activity activity) { - RestrictionsManager restrictionsManager = - (RestrictionsManager) activity.getSystemService(Context.RESTRICTIONS_SERVICE); - List<RestrictionEntry> restrictions = - restrictionsManager.getManifestRestrictions(PACKAGE_NAME_APP_RESTRICTION_SCHEMA); - for (RestrictionEntry restriction : restrictions) { - if (RESTRICTION_KEY_SAY_HELLO.equals(restriction.getKey())) { - mDefaultValueRestrictionSayHello = restriction.getSelectedState(); - } - } + private void saveMessage(Activity activity, String message) { + mCurrentRestrictions.putString(RESTRICTION_KEY_MESSAGE, message); + saveRestrictions(activity); + editPreferences(activity).putString(RESTRICTION_KEY_MESSAGE, message).apply(); } /** - * Returns whether the AppRestrictionSchema is currently allowed to say hello to its user. Note - * that a profile/device owner needs to remember each restriction value on its own. + * Saves the value for the "number" restriction of AppRestrictionSchema. * * @param activity The activity - * @return True if the AppRestrictionSchema is allowed to say hello + * @param number The value to be set for the restriction. */ - private boolean canSayHello(Activity activity) { - SharedPreferences prefs = activity.getSharedPreferences(PREFS_KEY, Context.MODE_PRIVATE); - return prefs.getBoolean(RESTRICTION_KEY_SAY_HELLO, mDefaultValueRestrictionSayHello); + private void saveNumber(Activity activity, int number) { + mCurrentRestrictions.putInt(RESTRICTION_KEY_NUMBER, number); + saveRestrictions(activity); + editPreferences(activity).putInt(RESTRICTION_KEY_NUMBER, number).apply(); } /** - * Sets the value for the "cay_say_hello" restriction of AppRestrictionSchema. + * Saves the value for the "rank" restriction of AppRestrictionSchema. * * @param activity The activity - * @param allow The value to be set for the restriction. + * @param rank The value to be set for the restriction. */ - private void allowSayHello(Activity activity, boolean allow) { + private void saveRank(Activity activity, String rank) { + mCurrentRestrictions.putString(RESTRICTION_KEY_RANK, rank); + saveRestrictions(activity); + editPreferences(activity).putString(RESTRICTION_KEY_RANK, rank).apply(); + } + + private void addApproval(Activity activity, String approval) { + List<String> approvals = new ArrayList<>(Arrays.asList( + mCurrentRestrictions.getStringArray(RESTRICTION_KEY_APPROVALS))); + if (approvals.contains(approval)) { + return; + } + approvals.add(approval); + saveApprovals(activity, approvals.toArray(new String[approvals.size()])); + } + + private void removeApproval(Activity activity, String approval) { + List<String> approvals = new ArrayList<>(Arrays.asList( + mCurrentRestrictions.getStringArray(RESTRICTION_KEY_APPROVALS))); + if (!approval.contains(approval)) { + return; + } + approvals.remove(approval); + saveApprovals(activity, approvals.toArray(new String[approvals.size()])); + } + + /** + * Saves the value for the "approvals" restriction of AppRestrictionSchema. + * + * @param activity The activity + * @param approvals The value to be set for the restriction. + */ + private void saveApprovals(Activity activity, String[] approvals) { + mCurrentRestrictions.putStringArray(RESTRICTION_KEY_APPROVALS, approvals); + saveRestrictions(activity); + editPreferences(activity).putString(RESTRICTION_KEY_APPROVALS, + TextUtils.join(DELIMETER, approvals)).apply(); + } + + private void saveRestrictions(Activity activity) { DevicePolicyManager devicePolicyManager = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); - Bundle restrictions = new Bundle(); - restrictions.putBoolean(RESTRICTION_KEY_SAY_HELLO, allow); devicePolicyManager.setApplicationRestrictions( EnforcerDeviceAdminReceiver.getComponentName(activity), - PACKAGE_NAME_APP_RESTRICTION_SCHEMA, restrictions); - // The profile/device owner needs to remember the current state of restrictions on its own - activity.getSharedPreferences(PREFS_KEY, Context.MODE_PRIVATE) - .edit() - .putBoolean(RESTRICTION_KEY_SAY_HELLO, allow) - .apply(); - Toast.makeText(activity, allow ? R.string.allowed : R.string.disallowed, - Toast.LENGTH_SHORT).show(); + Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA, mCurrentRestrictions); + } + + private SharedPreferences.Editor editPreferences(Activity activity) { + return activity.getSharedPreferences(PREFS_KEY, Context.MODE_PRIVATE).edit(); + } + + /** + * Sequential search + * + * @param array The string array + * @param s The string to search for + * @return Index if found. -1 if not found. + */ + private int search(String[] array, String s) { + for (int i = 0; i < array.length; ++i) { + if (s.equals(array[i])) { + return i; + } + } + return -1; } } diff --git a/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/Constants.java b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/Constants.java new file mode 100644 index 00000000..bb4e958c --- /dev/null +++ b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/Constants.java @@ -0,0 +1,27 @@ +/* + * 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.apprestrictionenforcer; + +public interface Constants { + + /** + * Package name of the AppRestrictionSchema sample. + */ + public static final String PACKAGE_NAME_APP_RESTRICTION_SCHEMA + = "com.example.android.apprestrictionschema"; + +} diff --git a/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/EasyTextWatcher.java b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/EasyTextWatcher.java new file mode 100644 index 00000000..8e0abb44 --- /dev/null +++ b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/EasyTextWatcher.java @@ -0,0 +1,38 @@ +/* + * 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.apprestrictionenforcer; + +import android.text.TextWatcher; + +/** + * This is a wrapper around {@link TextWatcher} that overrides + * {@link TextWatcher#beforeTextChanged(CharSequence, int, int, int)} and + * {@link TextWatcher#onTextChanged(CharSequence, int, int, int)} with empty bodies. + */ +public abstract class EasyTextWatcher implements TextWatcher { + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // Do nothing + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + // Do nothing + } + +} diff --git a/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/MainActivity.java b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/MainActivity.java index 72224e17..c6b012be 100644 --- a/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/MainActivity.java +++ b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/MainActivity.java @@ -18,24 +18,44 @@ package com.example.android.apprestrictionenforcer; import android.app.admin.DevicePolicyManager; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.os.Bundle; import android.support.v4.app.FragmentActivity; -public class MainActivity extends FragmentActivity { +public class MainActivity extends FragmentActivity implements StatusFragment.StatusUpdatedListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_real); if (null == savedInstanceState) { - DevicePolicyManager manager = (DevicePolicyManager) - getSystemService(Context.DEVICE_POLICY_SERVICE); - if (manager.isProfileOwnerApp(getApplicationContext().getPackageName())) { - // If the managed profile is already set up, we show the main screen. - showMainFragment(); - } else { - // If not, we show the set up screen. + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); + PackageManager packageManager = getPackageManager(); + if (!devicePolicyManager.isProfileOwnerApp(getApplicationContext().getPackageName())) { + // If the managed profile is not yet set up, we show the setup screen. showSetupProfile(); + } else { + try { + ApplicationInfo info = packageManager.getApplicationInfo( + Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA, + PackageManager.GET_UNINSTALLED_PACKAGES); + if (0 == (info.flags & ApplicationInfo.FLAG_INSTALLED)) { + // Need to reinstall the sample app + showStatusProfile(); + } else if (devicePolicyManager.isApplicationHidden( + EnforcerDeviceAdminReceiver.getComponentName(this), + Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA)) { + // The app is installed but hidden in this profile + showStatusProfile(); + } else { + // Everything is clear; show the main screen + showMainFragment(); + } + } catch (PackageManager.NameNotFoundException e) { + showStatusProfile(); + } } } } @@ -46,10 +66,21 @@ public class MainActivity extends FragmentActivity { .commit(); } + private void showStatusProfile() { + getSupportFragmentManager().beginTransaction() + .replace(R.id.container, new StatusFragment()) + .commit(); + } + private void showMainFragment() { getSupportFragmentManager().beginTransaction() .replace(R.id.container, new AppRestrictionEnforcerFragment()) .commit(); } + @Override + public void onStatusUpdated() { + showMainFragment(); + } + } diff --git a/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/StatusFragment.java b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/StatusFragment.java new file mode 100644 index 00000000..f4a4eb79 --- /dev/null +++ b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/StatusFragment.java @@ -0,0 +1,136 @@ +/* + * 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.apprestrictionenforcer; + +import android.app.Activity; +import android.app.admin.DevicePolicyManager; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +/** + * Provides UI for enabling the target app in this profile. The status of the app can be + * uninstalled, hidden, or enabled depending on the situations. This fragment shows suitable + * controls for each status. + */ +public class StatusFragment extends Fragment implements View.OnClickListener { + + private TextView mTextStatus; + private Button mButtonUnhide; + private StatusUpdatedListener mListener; + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_status, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + mTextStatus = (TextView) view.findViewById(R.id.status); + mButtonUnhide = (Button) view.findViewById(R.id.unhide); + mButtonUnhide.setOnClickListener(this); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + mListener = (StatusUpdatedListener) activity; + } + + @Override + public void onDetach() { + mListener = null; + super.onDetach(); + } + + @Override + public void onResume() { + super.onResume(); + updateUi(getActivity()); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.unhide: { + unhideApp(getActivity()); + break; + } + } + } + + private void updateUi(Activity activity) { + PackageManager packageManager = activity.getPackageManager(); + try { + ApplicationInfo info = packageManager.getApplicationInfo( + Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA, + PackageManager.GET_UNINSTALLED_PACKAGES); + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE); + if ((info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { + if (!devicePolicyManager.isApplicationHidden( + EnforcerDeviceAdminReceiver.getComponentName(activity), + Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA)) { + // The app is ready to enforce restrictions + // This is unlikely to happen in this sample as unhideApp() handles it. + mListener.onStatusUpdated(); + } else { + // The app is installed but hidden in this profile + mTextStatus.setText(R.string.status_not_activated); + mButtonUnhide.setVisibility(View.VISIBLE); + } + } else { + // Need to reinstall the sample app + mTextStatus.setText(R.string.status_need_reinstall); + mButtonUnhide.setVisibility(View.GONE); + } + } catch (PackageManager.NameNotFoundException e) { + // Need to reinstall the sample app + mTextStatus.setText(R.string.status_need_reinstall); + mButtonUnhide.setVisibility(View.GONE); + } + } + + /** + * Unhides the AppRestrictionSchema sample in case it is hidden in this profile. + * + * @param activity The activity + */ + private void unhideApp(Activity activity) { + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE); + devicePolicyManager.setApplicationHidden( + EnforcerDeviceAdminReceiver.getComponentName(activity), + Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA, false); + Toast.makeText(activity, "Enabled the app", Toast.LENGTH_SHORT).show(); + mListener.onStatusUpdated(); + } + + public interface StatusUpdatedListener { + public void onStatusUpdated(); + } + +} diff --git a/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_app_restriction_enforcer.xml b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_app_restriction_enforcer.xml index e6c50a24..01181916 100644 --- a/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_app_restriction_enforcer.xml +++ b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_app_restriction_enforcer.xml @@ -14,31 +14,111 @@ See the License for the specific language governing permissions and limitations under the License. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:paddingBottom="@dimen/vertical_page_margin" - android:paddingLeft="@dimen/horizontal_page_margin" - android:paddingRight="@dimen/horizontal_page_margin" - android:paddingTop="@dimen/vertical_page_margin"> - - <TextView - android:id="@+id/status" + android:layout_height="match_parent"> + + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/status_not_installed" /> + android:orientation="vertical" + android:paddingBottom="@dimen/vertical_page_margin" + android:paddingLeft="@dimen/horizontal_page_margin" + android:paddingRight="@dimen/horizontal_page_margin" + android:paddingTop="@dimen/vertical_page_margin"> - <Button - android:id="@+id/unhide" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/unhide" /> - <Switch - android:id="@+id/say_hello" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/allow_saying_hello" /> + <Switch + android:id="@+id/say_hello" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/allow_saying_hello"/> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/vertical_page_margin" + android:orientation="horizontal"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:labelFor="@id/message" + android:text="@string/message"/> + + <EditText + android:id="@id/message" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:inputType="text" + android:maxLines="1"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/vertical_page_margin" + android:orientation="horizontal"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:labelFor="@id/number" + android:text="@string/number"/> + + <EditText + android:id="@id/number" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:inputType="number" + android:maxLines="1"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/vertical_page_margin" + android:orientation="horizontal"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/rank"/> + + <Spinner + android:id="@+id/rank" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/margin_small"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/vertical_page_margin" + android:orientation="horizontal"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/approvals"/> + + <LinearLayout + android:id="@+id/approvals" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/margin_small" + android:orientation="vertical"/> + + </LinearLayout> + + </LinearLayout> -</LinearLayout> +</ScrollView> diff --git a/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_status.xml b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_status.xml new file mode 100644 index 00000000..a2d60eb7 --- /dev/null +++ b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_status.xml @@ -0,0 +1,39 @@ +<?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:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:paddingBottom="@dimen/vertical_page_margin" + android:paddingLeft="@dimen/horizontal_page_margin" + android:paddingRight="@dimen/horizontal_page_margin" + android:paddingTop="@dimen/vertical_page_margin"> + + <TextView + android:id="@+id/status" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/status_not_installed"/> + + <Button + android:id="@+id/unhide" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/unhide"/> + +</LinearLayout> diff --git a/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/layout/separator.xml b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/layout/separator.xml new file mode 100644 index 00000000..6927d801 --- /dev/null +++ b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/layout/separator.xml @@ -0,0 +1,22 @@ +<?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. +--> +<View xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginBottom="@dimen/margin_medium" + android:layout_marginTop="@dimen/margin_medium" + android:background="#9000"/> diff --git a/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/values/ids.xml b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/values/ids.xml new file mode 100644 index 00000000..04ba4ec2 --- /dev/null +++ b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/values/ids.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> + <item name="message" type="id"/> + <item name="number" type="id"/> + <item name="approval" type="id"/> +</resources> diff --git a/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/values/strings.xml b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/values/strings.xml index 3029e046..e35daee3 100644 --- a/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/values/strings.xml +++ b/prebuilts/gradle/AppRestrictionEnforcer/Application/src/main/res/values/strings.xml @@ -25,4 +25,8 @@ <string name="allowed">Allowed</string> <string name="disallowed">Disallowed</string> <string name="profile_name">AppRestrictionEnforcer </string> + <string name="message">Message: </string> + <string name="number">Number: </string> + <string name="rank">Rank: </string> + <string name="approvals">Approvals: </string> </resources> diff --git a/prebuilts/gradle/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.properties index 0c71e760..f2e517b2 100644 --- a/prebuilts/gradle/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.properties +++ b/prebuilts/gradle/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Wed Apr 10 15:27:10 PDT 2013 +#Mon Dec 01 16:00:44 JST 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/prebuilts/gradle/AppRestrictionSchema/Application/build.gradle b/prebuilts/gradle/AppRestrictionSchema/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/AppRestrictionSchema/Application/build.gradle +++ b/prebuilts/gradle/AppRestrictionSchema/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/AppRestrictionSchema/Application/src/main/java/com/example/android/apprestrictionschema/AppRestrictionSchemaFragment.java b/prebuilts/gradle/AppRestrictionSchema/Application/src/main/java/com/example/android/apprestrictionschema/AppRestrictionSchemaFragment.java index 76f024f3..7b8dba83 100644 --- a/prebuilts/gradle/AppRestrictionSchema/Application/src/main/java/com/example/android/apprestrictionschema/AppRestrictionSchemaFragment.java +++ b/prebuilts/gradle/AppRestrictionSchema/Application/src/main/java/com/example/android/apprestrictionschema/AppRestrictionSchemaFragment.java @@ -17,10 +17,12 @@ package com.example.android.apprestrictionschema; import android.content.Context; +import android.content.RestrictionEntry; import android.content.RestrictionsManager; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -30,6 +32,8 @@ import android.widget.Toast; import com.example.android.common.logger.Log; +import java.util.List; + /** * Pressing the button on this fragment pops up a simple Toast message. The button is enabled or * disabled according to the restrictions set by device/profile owner. You can use the @@ -40,9 +44,21 @@ public class AppRestrictionSchemaFragment extends Fragment implements View.OnCli // Tag for the logger private static final String TAG = "AppRestrictionSchemaFragment"; + private static final String KEY_CAN_SAY_HELLO = "can_say_hello"; + private static final String KEY_MESSAGE = "message"; + private static final String KEY_NUMBER = "number"; + private static final String KEY_RANK = "rank"; + private static final String KEY_APPROVALS = "approvals"; + + // Message to show when the button is clicked (String restriction) + private String mMessage; + // UI Components private TextView mTextSayHello; private Button mButtonSayHello; + private TextView mTextNumber; + private TextView mTextRank; + private TextView mTextApprovals; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @@ -54,48 +70,103 @@ public class AppRestrictionSchemaFragment extends Fragment implements View.OnCli public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { mTextSayHello = (TextView) view.findViewById(R.id.say_hello_explanation); mButtonSayHello = (Button) view.findViewById(R.id.say_hello); + mTextNumber = (TextView) view.findViewById(R.id.your_number); + mTextRank = (TextView) view.findViewById(R.id.your_rank); + mTextApprovals = (TextView) view.findViewById(R.id.approvals_you_have); mButtonSayHello.setOnClickListener(this); } @Override public void onResume() { super.onResume(); - // Update the UI according to the configured restrictions - RestrictionsManager restrictionsManager = + resolveRestrictions(); + } + + private void resolveRestrictions() { + RestrictionsManager manager = (RestrictionsManager) getActivity().getSystemService(Context.RESTRICTIONS_SERVICE); - Bundle restrictions = restrictionsManager.getApplicationRestrictions(); - updateUI(restrictions); + Bundle restrictions = manager.getApplicationRestrictions(); + List<RestrictionEntry> entries = manager.getManifestRestrictions(getActivity().getApplicationContext().getPackageName()); + for (RestrictionEntry entry : entries) { + String key = entry.getKey(); + Log.d(TAG, "key: " + key); + if (key.equals(KEY_CAN_SAY_HELLO)) { + updateCanSayHello(entry, restrictions); + } else if (key.equals(KEY_MESSAGE)) { + updateMessage(entry, restrictions); + } else if (key.equals(KEY_NUMBER)) { + updateNumber(entry, restrictions); + } else if (key.equals(KEY_RANK)) { + updateRank(entry, restrictions); + } else if (key.equals(KEY_APPROVALS)) { + updateApprovals(entry, restrictions); + } + } + } + + private void updateCanSayHello(RestrictionEntry entry, Bundle restrictions) { + boolean canSayHello; + if (restrictions == null || !restrictions.containsKey(KEY_CAN_SAY_HELLO)) { + canSayHello = entry.getSelectedState(); + } else { + canSayHello = restrictions.getBoolean(KEY_CAN_SAY_HELLO); + } + mTextSayHello.setText(canSayHello ? + R.string.explanation_can_say_hello_true : + R.string.explanation_can_say_hello_false); + mButtonSayHello.setEnabled(canSayHello); } - private void updateUI(Bundle restrictions) { - if (canSayHello(restrictions)) { - mTextSayHello.setText(R.string.explanation_can_say_hello_true); - mButtonSayHello.setEnabled(true); + private void updateMessage(RestrictionEntry entry, Bundle restrictions) { + if (restrictions == null || !restrictions.containsKey(KEY_MESSAGE)) { + mMessage = entry.getSelectedString(); } else { - mTextSayHello.setText(R.string.explanation_can_say_hello_false); - mButtonSayHello.setEnabled(false); + mMessage = restrictions.getString(KEY_MESSAGE); } } - /** - * Returns the current status of the restriction. - * - * @param restrictions The application restrictions - * @return True if the app is allowed to say hello - */ - private boolean canSayHello(Bundle restrictions) { - final boolean defaultValue = false; - boolean canSayHello = restrictions == null ? defaultValue : - restrictions.getBoolean("can_say_hello", defaultValue); - Log.d(TAG, "canSayHello: " + canSayHello); - return canSayHello; + private void updateNumber(RestrictionEntry entry, Bundle restrictions) { + int number; + if (restrictions == null || !restrictions.containsKey(KEY_NUMBER)) { + number = entry.getIntValue(); + } else { + number = restrictions.getInt(KEY_NUMBER); + } + mTextNumber.setText(getString(R.string.your_number, number)); + } + + private void updateRank(RestrictionEntry entry, Bundle restrictions) { + String rank; + if (restrictions == null || !restrictions.containsKey(KEY_RANK)) { + rank = entry.getSelectedString(); + } else { + rank = restrictions.getString(KEY_RANK); + } + mTextRank.setText(getString(R.string.your_rank, rank)); + } + + private void updateApprovals(RestrictionEntry entry, Bundle restrictions) { + String[] approvals; + if (restrictions == null || !restrictions.containsKey(KEY_APPROVALS)) { + approvals = entry.getAllSelectedStrings(); + } else { + approvals = restrictions.getStringArray(KEY_APPROVALS); + } + String text; + if (approvals == null || approvals.length == 0) { + text = getString(R.string.none); + } else { + text = TextUtils.join(", ", approvals); + } + mTextApprovals.setText(getString(R.string.approvals_you_have, text)); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.say_hello: { - Toast.makeText(getActivity(), R.string.message_hello, Toast.LENGTH_SHORT).show(); + Toast.makeText(getActivity(), getString(R.string.message, mMessage), + Toast.LENGTH_SHORT).show(); break; } } diff --git a/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/layout/fragment_app_restriction_schema.xml b/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/layout/fragment_app_restriction_schema.xml index fc5e23dc..18ca0a4d 100644 --- a/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/layout/fragment_app_restriction_schema.xml +++ b/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/layout/fragment_app_restriction_schema.xml @@ -14,24 +14,60 @@ 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:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:padding="@dimen/margin_medium"> - - <TextView - android:id="@+id/say_hello_explanation" + + +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/explanation_can_say_hello_true" - android:textAppearance="?android:attr/textAppearanceMedium" /> + android:orientation="vertical" + android:padding="@dimen/margin_medium"> - <Button - android:id="@+id/say_hello" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="@dimen/margin_medium" - android:text="@string/action_can_say_hello" /> + <TextView + android:id="@+id/say_hello_explanation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + tools:text="@string/explanation_can_say_hello_true"/> + + <Button + android:id="@+id/say_hello" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/margin_medium" + android:text="@string/action_can_say_hello"/> + + <include layout="@layout/separator"/> + + <TextView + android:id="@+id/your_number" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + tools:text="@string/your_number"/> + + <include layout="@layout/separator"/> + + <TextView + android:id="@+id/your_rank" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + tools:text="@string/your_rank"/> + + <include layout="@layout/separator"/> + + <TextView + android:id="@+id/approvals_you_have" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + tools:text="@string/approvals_you_have"/> + + </LinearLayout> -</LinearLayout> +</ScrollView> diff --git a/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/layout/separator.xml b/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/layout/separator.xml new file mode 100644 index 00000000..6927d801 --- /dev/null +++ b/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/layout/separator.xml @@ -0,0 +1,22 @@ +<?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. +--> +<View xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginBottom="@dimen/margin_medium" + android:layout_marginTop="@dimen/margin_medium" + android:background="#9000"/> diff --git a/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/values/restriction_values.xml b/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/values/restriction_values.xml new file mode 100644 index 00000000..558d097f --- /dev/null +++ b/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/values/restriction_values.xml @@ -0,0 +1,77 @@ +<?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> + + <!-- Bool restriction --> + <string name="title_can_say_hello">Can say hello</string> + <string name="description_can_say_hello">Whether the app can say hello to the user</string> + <bool name="default_can_say_hello">false</bool> + + <!-- String restriction --> + <string name="title_message">Message</string> + <string name="description_message">A message string to show</string> + <string name="default_message">Hello!</string> + + <!-- Integer restriction --> + <string name="title_number">Number</string> + <string name="description_number">Sample integer value</string> + <integer name="default_number">32582657</integer> + + <!-- Choice restriction --> + <string name="title_rank">Rank</string> + <string name="description_rank">Rank of the user</string> + <string-array name="entries_rank"> + <item>Apprentice</item> + <item>Intermediate</item> + <item>Master</item> + </string-array> + <string name="entry_value_rank_apprentice">apprentice</string> + <string name="entry_value_rank_intermediate">intermediate</string> + <string name="entry_value_rank_master">master</string> + <string-array name="entry_values_rank"> + <item>@string/entry_value_rank_apprentice</item> + <item>@string/entry_value_rank_intermediate</item> + <item>@string/entry_value_rank_master</item> + </string-array> + <string name="default_rank">@string/entry_value_rank_apprentice</string> + + <!-- Multi-select restriction --> + <string name="title_approvals">Approvals</string> + <string name="description_approvals">Approvals</string> + <string-array name="entries_approvals"> + <item>Read</item> + <item>Write</item> + <item>Execute</item> + </string-array> + <string name="entry_value_approvals_read">read</string> + <string name="entry_value_approvals_write">write</string> + <string name="entry_value_approvals_execute">execute</string> + <string-array name="entry_values_approvals"> + <item>@string/entry_value_approvals_read</item> + <item>@string/entry_value_approvals_write</item> + <item>@string/entry_value_approvals_execute</item> + </string-array> + <string-array name="default_approvals"> + <!-- Empty --> + </string-array> + + <!-- Hidden restriction --> + <string name="title_secret_code">Secret code</string> + <string name="description_secret_code">This restriction is hidden and will not be shown to the administrator.</string> + <string name="default_secret_code">(Hidden restriction must have some default value)</string> + +</resources> diff --git a/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/values/strings.xml b/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/values/strings.xml index b8ef110b..6dce123f 100644 --- a/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/values/strings.xml +++ b/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/values/strings.xml @@ -16,11 +16,14 @@ limitations under the License. --> <resources> - <string name="title_can_say_hello">Can say hello</string> - <string name="description_can_say_hello">Whether the app can say hello to the user</string> <string name="explanation_can_say_hello_true">I can say hello to you.</string> <string name="explanation_can_say_hello_false">I am restricted from saying hello to you.</string> <string name="action_can_say_hello">Say hello</string> - <string name="message_hello">Hello!</string> + <string name="message">All I can say is \"%s\".</string> -</resources>
\ No newline at end of file + <string name="your_number">Your number: %d</string> + <string name="your_rank">Your rank: %s</string> + <string name="approvals_you_have">Approvals you have: %s</string> + <string name="none">none</string> + +</resources> diff --git a/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/xml/app_restrictions.xml b/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/xml/app_restrictions.xml index 409527fc..9e47f458 100644 --- a/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/xml/app_restrictions.xml +++ b/prebuilts/gradle/AppRestrictionSchema/Application/src/main/res/xml/app_restrictions.xml @@ -16,11 +16,55 @@ limitations under the License. --> <restrictions xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- + Refer to the javadoc of RestrictionsManager for detail of this file. + https://developer.android.com/reference/android/content/RestrictionsManager.html + --> + <restriction - android:defaultValue="false" + android:defaultValue="@bool/default_can_say_hello" android:description="@string/description_can_say_hello" android:key="can_say_hello" android:restrictionType="bool" - android:title="@string/title_can_say_hello" /> + android:title="@string/title_can_say_hello"/> + + <restriction + android:defaultValue="@string/default_message" + android:description="@string/description_message" + android:key="message" + android:restrictionType="string" + android:title="@string/title_message"/> + + <restriction + android:defaultValue="@integer/default_number" + android:description="@string/description_number" + android:key="number" + android:restrictionType="integer" + android:title="@string/title_number"/> + + <restriction + android:defaultValue="@string/default_rank" + android:description="@string/description_rank" + android:entries="@array/entries_rank" + android:entryValues="@array/entry_values_rank" + android:key="rank" + android:restrictionType="choice" + android:title="@string/title_rank"/> + + <restriction + android:defaultValue="@array/default_approvals" + android:description="@string/description_approvals" + android:entries="@array/entries_approvals" + android:entryValues="@array/entry_values_approvals" + android:key="approvals" + android:restrictionType="multi-select" + android:title="@string/title_approvals"/> + + <restriction + android:defaultValue="@string/default_secret_code" + android:description="@string/description_secret_code" + android:key="secret_code" + android:restrictionType="hidden" + android:title="@string/title_secret_code"/> </restrictions> diff --git a/prebuilts/gradle/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.properties index 0c71e760..fb79885e 100644 --- a/prebuilts/gradle/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.properties +++ b/prebuilts/gradle/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Wed Apr 10 15:27:10 PDT 2013 +#Mon Dec 01 11:44:58 JST 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/prebuilts/gradle/AppRestrictions/Application/build.gradle b/prebuilts/gradle/AppRestrictions/Application/build.gradle index f3cacbe1..3859b3ee 100644 --- a/prebuilts/gradle/AppRestrictions/Application/build.gradle +++ b/prebuilts/gradle/AppRestrictions/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/AppUsageStatistics/.google/packaging.yaml b/prebuilts/gradle/AppUsageStatistics/.google/packaging.yaml new file mode 100644 index 00000000..7e39ed2b --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/.google/packaging.yaml @@ -0,0 +1,17 @@ +# GOOGLE SAMPLE PACKAGING DATA +# +# This file is used by Google as part of our samples packaging process. +# End users may safely ignore this file. It has no relevance to other systems. +--- +status: DRAFT +technologies: [Android] +categories: [System] +languages: [Java] +solutions: [Mobile] +github: android-AppUsageStatistics +level: INTERMEDIATE +icon: screenshots/web-icon.png +apiRefs: + - android:android.app.usage.UsageStats + - android:android.app.usage.UsageStatsManager +license: apache2 diff --git a/prebuilts/gradle/AppUsageStatistics/Application/build.gradle b/prebuilts/gradle/AppUsageStatistics/Application/build.gradle new file mode 100644 index 00000000..aecc5fd6 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/build.gradle @@ -0,0 +1,72 @@ +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:1.0.0' + } +} + +apply plugin: 'com.android.application' + +repositories { + jcenter() +} + + +dependencies { + + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" + + compile "com.android.support:recyclerview-v7:+" + compile "com.android.support:appcompat-v7:21.+" +} + +// The sample build uses multiple directories to +// keep boilerplate and common code separate from +// the main sample code. +List<String> dirs = [ + 'main', // main sample code; look here for the interesting stuff. + 'common', // components that are reused by multiple samples + 'template'] // boilerplate code that is generated by the sample template process + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 21 + targetSdkVersion 21 + } + + sourceSets { + main { + dirs.each { dir -> + java.srcDirs "src/${dir}/java" + res.srcDirs "src/${dir}/res" + } + } + androidTest.setRoot('tests') + androidTest.java.srcDirs = ['tests/src'] + + } + +} + + + + + + + + + + + + + + + diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/AndroidManifest.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/AndroidManifest.xml new file mode 100644 index 00000000..2726b4a2 --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/AppUsageStatisticsActivity.java b/prebuilts/gradle/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/AppUsageStatisticsActivity.java new file mode 100644 index 00000000..4def465f --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/AppUsageStatisticsFragment.java b/prebuilts/gradle/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/AppUsageStatisticsFragment.java new file mode 100644 index 00000000..50a72e77 --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/CustomUsageStats.java b/prebuilts/gradle/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/CustomUsageStats.java new file mode 100644 index 00000000..b5b15c4e --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/UsageListAdapter.java b/prebuilts/gradle/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/UsageListAdapter.java new file mode 100644 index 00000000..ab1d0376 --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-hdpi/ic_default_app_launcher.png b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-hdpi/ic_default_app_launcher.png Binary files differnew file mode 100644 index 00000000..96a442e5 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-hdpi/ic_default_app_launcher.png diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-hdpi/ic_launcher.png b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100755 index 00000000..3cf5e8b4 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-hdpi/tile.9.png b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-hdpi/tile.9.png Binary files differnew file mode 100644 index 00000000..13586288 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-hdpi/tile.9.png diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-mdpi/ic_default_app_launcher.png b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-mdpi/ic_default_app_launcher.png Binary files differnew file mode 100644 index 00000000..359047df --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-mdpi/ic_default_app_launcher.png diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-mdpi/ic_launcher.png b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100755 index 00000000..51553c5d --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-xhdpi/ic_default_app_launcher.png b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-xhdpi/ic_default_app_launcher.png Binary files differnew file mode 100644 index 00000000..71c6d760 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-xhdpi/ic_default_app_launcher.png diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100755 index 00000000..52480002 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-xxhdpi/ic_default_app_launcher.png b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-xxhdpi/ic_default_app_launcher.png Binary files differnew file mode 100644 index 00000000..4df18946 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-xxhdpi/ic_default_app_launcher.png diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100755 index 00000000..7f162009 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/layout/activity_app_usage_statistics.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/layout/activity_app_usage_statistics.xml new file mode 100644 index 00000000..2627c8b7 --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/layout/activity_main.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/layout/activity_main.xml new file mode 100755 index 00000000..be1aa49d --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/layout/activity_main.xml @@ -0,0 +1,36 @@ +<!-- + 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. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <LinearLayout style="@style/Widget.SampleMessageTile" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView style="@style/Widget.SampleMessage" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/horizontal_page_margin" + android:layout_marginRight="@dimen/horizontal_page_margin" + android:layout_marginTop="@dimen/vertical_page_margin" + android:layout_marginBottom="@dimen/vertical_page_margin" + android:text="@string/intro_message" /> + </LinearLayout> +</LinearLayout> diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/layout/fragment_app_usage_statistics.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/layout/fragment_app_usage_statistics.xml new file mode 100644 index 00000000..1d567b76 --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/layout/usage_row.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/layout/usage_row.xml new file mode 100644 index 00000000..c16f039e --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-sw600dp/template-dimens.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-sw600dp/template-dimens.xml new file mode 100644 index 00000000..22074a2b --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-sw600dp/template-dimens.xml @@ -0,0 +1,24 @@ +<!-- + 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. + --> + +<resources> + + <!-- Semantic definitions --> + + <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen> + <dimen name="vertical_page_margin">@dimen/margin_medium</dimen> + +</resources> diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-sw600dp/template-styles.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-sw600dp/template-styles.xml new file mode 100644 index 00000000..03d19741 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-sw600dp/template-styles.xml @@ -0,0 +1,25 @@ +<!-- + 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. + --> + +<resources> + + <style name="Widget.SampleMessage"> + <item name="android:textAppearance">?android:textAppearanceLarge</item> + <item name="android:lineSpacingMultiplier">1.2</item> + <item name="android:shadowDy">-6.5</item> + </style> + +</resources> diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-v11/template-styles.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-v11/template-styles.xml new file mode 100644 index 00000000..8c1ea66f --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-v11/template-styles.xml @@ -0,0 +1,22 @@ +<!-- + 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. + --> + +<resources> + + <!-- Activity themes --> + <style name="Theme.Base" parent="android:Theme.Holo.Light" /> + +</resources> diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-v21/base-colors.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-v21/base-colors.xml new file mode 100644 index 00000000..34c9cd13 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-v21/base-colors.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<resources> + + +</resources> diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-v21/base-template-styles.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-v21/base-template-styles.xml new file mode 100644 index 00000000..0b2948f7 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values-v21/base-template-styles.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<resources> + + <!-- Activity themes --> + <style name="Theme.Base" parent="android:Theme.Material.Light"> + </style> + +</resources> diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/base-strings.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/base-strings.xml new file mode 100644 index 00000000..9a92da8c --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/base-strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<resources> + <string name="app_name">AppUsageStatistics</string> + <string name="intro_message"> + <![CDATA[ + + + This sample explains how to use App usage statistics API, which was introduced + in Android 5.0. + + + ]]> + </string> +</resources> diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/dimens.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/dimens.xml new file mode 100644 index 00000000..d1741c33 --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/navigation_items.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/navigation_items.xml new file mode 100644 index 00000000..b36a4a58 --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/strings.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/strings.xml new file mode 100644 index 00000000..2caaf900 --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/styles.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/styles.xml new file mode 100644 index 00000000..d4002764 --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/template-dimens.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/template-dimens.xml new file mode 100644 index 00000000..39e710b5 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/template-dimens.xml @@ -0,0 +1,32 @@ +<!-- + 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. + --> + +<resources> + + <!-- Define standard dimensions to comply with Holo-style grids and rhythm. --> + + <dimen name="margin_tiny">4dp</dimen> + <dimen name="margin_small">8dp</dimen> + <dimen name="margin_medium">16dp</dimen> + <dimen name="margin_large">32dp</dimen> + <dimen name="margin_huge">64dp</dimen> + + <!-- Semantic definitions --> + + <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen> + <dimen name="vertical_page_margin">@dimen/margin_medium</dimen> + +</resources> diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/template-styles.xml b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/template-styles.xml new file mode 100644 index 00000000..6e7d593d --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/res/values/template-styles.xml @@ -0,0 +1,42 @@ +<!-- + 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. + --> + +<resources> + + <!-- Activity themes --> + + <style name="Theme.Base" parent="android:Theme.Light" /> + + <style name="Theme.Sample" parent="Theme.Base" /> + + <style name="AppTheme" parent="Theme.Sample" /> + <!-- Widget styling --> + + <style name="Widget" /> + + <style name="Widget.SampleMessage"> + <item name="android:textAppearance">?android:textAppearanceMedium</item> + <item name="android:lineSpacingMultiplier">1.1</item> + </style> + + <style name="Widget.SampleMessageTile"> + <item name="android:background">@drawable/tile</item> + <item name="android:shadowColor">#7F000000</item> + <item name="android:shadowDy">-3.5</item> + <item name="android:shadowRadius">2</item> + </style> + +</resources> diff --git a/prebuilts/gradle/AppUsageStatistics/Application/tests/src/com/example/android/appusagestatistics/AppUsageStatisticsActivityTests.java b/prebuilts/gradle/AppUsageStatistics/Application/tests/src/com/example/android/appusagestatistics/AppUsageStatisticsActivityTests.java new file mode 100644 index 00000000..f2e3ea91 --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/Application/tests/src/com/example/android/appusagestatistics/AppUsageStatisticsFragmentTests.java b/prebuilts/gradle/AppUsageStatistics/Application/tests/src/com/example/android/appusagestatistics/AppUsageStatisticsFragmentTests.java new file mode 100644 index 00000000..d8adb1ce --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/CONTRIBUTING.md b/prebuilts/gradle/AppUsageStatistics/CONTRIBUTING.md new file mode 100644 index 00000000..faa8b5c6 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/CONTRIBUTING.md @@ -0,0 +1,35 @@ +# How to become a contributor and submit your own code + +## Contributor License Agreements + +We'd love to accept your sample apps and patches! Before we can take them, we +have to jump a couple of legal hurdles. + +Please fill out either the individual or corporate Contributor License Agreement (CLA). + + * If you are an individual writing original source code and you're sure you + own the intellectual property, then you'll need to sign an [individual CLA] + (https://cla.developers.google.com). + * If you work for a company that wants to allow you to contribute your work, + then you'll need to sign a [corporate CLA] + (https://cla.developers.google.com). + +Follow either of the two links above to access the appropriate CLA and +instructions for how to sign and return it. Once we receive it, we'll be able to +accept your pull requests. + +## Contributing A Patch + +1. Submit an issue describing your proposed change to the repo in question. +1. The repo owner will respond to your issue promptly. +1. If your proposed change is accepted, and you haven't already done so, sign a + Contributor License Agreement (see details above). +1. Fork the desired repo, develop and test your code changes. +1. Ensure that your code adheres to the existing style in the sample to which + you are contributing. Refer to the + [Android Code Style Guide] + (https://source.android.com/source/code-style.html) for the + recommended coding standards for this organization. +1. Ensure that your code has an appropriate set of unit tests which all pass. +1. Submit a pull request. + diff --git a/prebuilts/gradle/AppUsageStatistics/LICENSE b/prebuilts/gradle/AppUsageStatistics/LICENSE new file mode 100644 index 00000000..1af981f5 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + 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. diff --git a/prebuilts/gradle/AppUsageStatistics/NOTICE b/prebuilts/gradle/AppUsageStatistics/NOTICE new file mode 100644 index 00000000..7eede3de --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/NOTICE @@ -0,0 +1,15 @@ +This sample uses the following software: + +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. diff --git a/prebuilts/gradle/AppUsageStatistics/README.md b/prebuilts/gradle/AppUsageStatistics/README.md new file mode 100644 index 00000000..daeb173c --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/README.md @@ -0,0 +1,96 @@ +Android AppUsageStatistics Sample +=================================== + +A basic app showing how to use App usage statistics API to let users collect statistics related +to usage of the applications. + +Introduction +------------ + +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) + +Pre-requisites +-------------- + +- Android SDK v21 +- Android Build Tools v21.1.1 +- Android Support Repository + +Screenshots +------------- + +<img src="screenshots/screenshot-1.png" height="400" alt="Screenshot"/> <img src="screenshots/screenshot-2.png" height="400" alt="Screenshot"/> + +Getting Started +--------------- + +This sample uses the Gradle build system. To build this project, use the +"gradlew build" command or use "Import Project" in Android Studio. + +Support +------- + +- Google+ Community: https://plus.google.com/communities/105153134372062985968 +- Stack Overflow: http://stackoverflow.com/questions/tagged/android + +If you've found an error in this sample, please file an issue: +https://github.com/googlesamples/android-AppUsageStatistics + +Patches are encouraged, and may be submitted by forking this project and +submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details. + +License +------- + +Copyright 2014 The Android Open Source Project, Inc. + +Licensed to the Apache Software Foundation (ASF) under one or more contributor +license agreements. See the NOTICE file distributed with this work for +additional information regarding copyright ownership. The ASF licenses this +file to you 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. diff --git a/prebuilts/gradle/AppUsageStatistics/build.gradle b/prebuilts/gradle/AppUsageStatistics/build.gradle new file mode 100644 index 00000000..1dac6def --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/build.gradle @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/prebuilts/gradle/AppUsageStatistics/gradle/wrapper/gradle-wrapper.jar b/prebuilts/gradle/AppUsageStatistics/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 00000000..8c0fb64a --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/gradle/wrapper/gradle-wrapper.jar diff --git a/prebuilts/gradle/AppUsageStatistics/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/AppUsageStatistics/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..8a27ebfa --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/gradlew b/prebuilts/gradle/AppUsageStatistics/gradlew new file mode 100755 index 00000000..91a7e269 --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/gradlew.bat b/prebuilts/gradle/AppUsageStatistics/gradlew.bat new file mode 100644 index 00000000..aec99730 --- /dev/null +++ b/prebuilts/gradle/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/prebuilts/gradle/AppUsageStatistics/screenshots/screenshot-1.png b/prebuilts/gradle/AppUsageStatistics/screenshots/screenshot-1.png Binary files differnew file mode 100644 index 00000000..ab0da864 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/screenshots/screenshot-1.png diff --git a/prebuilts/gradle/AppUsageStatistics/screenshots/screenshot-2.png b/prebuilts/gradle/AppUsageStatistics/screenshots/screenshot-2.png Binary files differnew file mode 100644 index 00000000..7663ebdf --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/screenshots/screenshot-2.png diff --git a/prebuilts/gradle/AppUsageStatistics/screenshots/web-icon.png b/prebuilts/gradle/AppUsageStatistics/screenshots/web-icon.png Binary files differnew file mode 100755 index 00000000..68af9d0e --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/screenshots/web-icon.png diff --git a/prebuilts/gradle/AppUsageStatistics/settings.gradle b/prebuilts/gradle/AppUsageStatistics/settings.gradle new file mode 100644 index 00000000..9464a359 --- /dev/null +++ b/prebuilts/gradle/AppUsageStatistics/settings.gradle @@ -0,0 +1 @@ +include 'Application' diff --git a/prebuilts/gradle/BasicAccessibility/Application/build.gradle b/prebuilts/gradle/BasicAccessibility/Application/build.gradle index 8380768f..8b72299a 100644 --- a/prebuilts/gradle/BasicAccessibility/Application/build.gradle +++ b/prebuilts/gradle/BasicAccessibility/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BasicAndroidKeyStore/Application/build.gradle b/prebuilts/gradle/BasicAndroidKeyStore/Application/build.gradle index f3cacbe1..3859b3ee 100644 --- a/prebuilts/gradle/BasicAndroidKeyStore/Application/build.gradle +++ b/prebuilts/gradle/BasicAndroidKeyStore/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BasicContactables/.google/packaging.yaml b/prebuilts/gradle/BasicContactables/.google/packaging.yaml index c17e1fcc..d18be0c2 100644 --- a/prebuilts/gradle/BasicContactables/.google/packaging.yaml +++ b/prebuilts/gradle/BasicContactables/.google/packaging.yaml @@ -9,4 +9,12 @@ categories: [Content] languages: [Java] solutions: [Mobile] github: android-BasicContactables +level: INTERMEDIATE +icon: screenshots/icon-web.png +apiRefs: + - android:android.app.SearchManager + - android:android.widget.SearchView + - android:android.app.LoaderManager + - android:android.content.CursorLoader + - android:android.provider.ContactsContract.CommonDataKinds license: apache2 diff --git a/prebuilts/gradle/BasicContactables/Application/build.gradle b/prebuilts/gradle/BasicContactables/Application/build.gradle index f3cacbe1..3859b3ee 100644 --- a/prebuilts/gradle/BasicContactables/Application/build.gradle +++ b/prebuilts/gradle/BasicContactables/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BasicContactables/README.md b/prebuilts/gradle/BasicContactables/README.md index 883cd6c3..cd274c94 100644 --- a/prebuilts/gradle/BasicContactables/README.md +++ b/prebuilts/gradle/BasicContactables/README.md @@ -1,10 +1,25 @@ Android BasicContactables Sample =================================== -This sample demonstrates how to use the Contactables table to search for contacts. +This sample shows how to search for contacts, displaying a SearchView in the Action Bar for user input and implementing a query Cursor with CommonDataKinds.Contactables. -Query strings sent to the Contactables table will match both contact names and phone numbers, -reducing the number of queries your application needs to use when searching the contacts database! +Introduction +------------ + +This sample displays a [SearchView][1] in the Action Bar when the search icon is clicked. It then implements the [LoaderManager.LoaderCallbacks][2] interface to query the contacts table, using a [CursorLoader][3]. + +For details on how to implement the [SearchView][1], refer to the training guide [Setting up the search interface][4]. + +For details on how to implement the [LoaderManager.LoaderCallbacks][2] interface, refer to the [Using the LoaderManager Callbacks][5] guide. + +For details on how to query the contacts provider, refer to the [Contacts Provider Access][6] guide. + +[1]: http://developer.android.com/reference/android/widget/SearchView.html +[2]: http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html +[3]: http://developer.android.com/reference/android/content/CursorLoader.html +[4]: http://developer.android.com/training/search/setup.html +[5]: http://developer.android.com/guide/components/loaders.html#callback +[6]: http://developer.android.com/guide/topics/providers/contacts-provider.html#Access Pre-requisites -------------- @@ -13,6 +28,11 @@ Pre-requisites - Android Build Tools v21.1.1 - Android Support Repository +Screenshots +------------- + +<img src="screenshots/1-main.png" height="400" alt="Screenshot"/> <img src="screenshots/2-search.png" height="400" alt="Screenshot"/> <img src="screenshots/3-results.png" height="400" alt="Screenshot"/> + Getting Started --------------- diff --git a/prebuilts/gradle/BasicContactables/screenshots/1-main.png b/prebuilts/gradle/BasicContactables/screenshots/1-main.png Binary files differnew file mode 100644 index 00000000..2c11a7d9 --- /dev/null +++ b/prebuilts/gradle/BasicContactables/screenshots/1-main.png diff --git a/prebuilts/gradle/BasicContactables/screenshots/2-search.png b/prebuilts/gradle/BasicContactables/screenshots/2-search.png Binary files differnew file mode 100644 index 00000000..b8b012f4 --- /dev/null +++ b/prebuilts/gradle/BasicContactables/screenshots/2-search.png diff --git a/prebuilts/gradle/BasicContactables/screenshots/3-results.png b/prebuilts/gradle/BasicContactables/screenshots/3-results.png Binary files differnew file mode 100644 index 00000000..48856ce6 --- /dev/null +++ b/prebuilts/gradle/BasicContactables/screenshots/3-results.png diff --git a/prebuilts/gradle/BasicContactables/screenshots/icon-web.png b/prebuilts/gradle/BasicContactables/screenshots/icon-web.png Binary files differnew file mode 100644 index 00000000..8ad9e149 --- /dev/null +++ b/prebuilts/gradle/BasicContactables/screenshots/icon-web.png diff --git a/prebuilts/gradle/BasicGestureDetect/Application/build.gradle b/prebuilts/gradle/BasicGestureDetect/Application/build.gradle index f3cacbe1..3859b3ee 100644 --- a/prebuilts/gradle/BasicGestureDetect/Application/build.gradle +++ b/prebuilts/gradle/BasicGestureDetect/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BasicImmersiveMode/Application/build.gradle b/prebuilts/gradle/BasicImmersiveMode/Application/build.gradle index bfed04fa..c6b8c26a 100644 --- a/prebuilts/gradle/BasicImmersiveMode/Application/build.gradle +++ b/prebuilts/gradle/BasicImmersiveMode/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BasicManagedProfile/Application/build.gradle b/prebuilts/gradle/BasicManagedProfile/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/BasicManagedProfile/Application/build.gradle +++ b/prebuilts/gradle/BasicManagedProfile/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BasicMediaDecoder/Application/build.gradle b/prebuilts/gradle/BasicMediaDecoder/Application/build.gradle index 5e57579a..d727e2a8 100644 --- a/prebuilts/gradle/BasicMediaDecoder/Application/build.gradle +++ b/prebuilts/gradle/BasicMediaDecoder/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BasicMediaRouter/Application/build.gradle b/prebuilts/gradle/BasicMediaRouter/Application/build.gradle index 5e57579a..d727e2a8 100644 --- a/prebuilts/gradle/BasicMediaRouter/Application/build.gradle +++ b/prebuilts/gradle/BasicMediaRouter/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BasicMultitouch/Application/build.gradle b/prebuilts/gradle/BasicMultitouch/Application/build.gradle index 90737fcc..3e25a83b 100644 --- a/prebuilts/gradle/BasicMultitouch/Application/build.gradle +++ b/prebuilts/gradle/BasicMultitouch/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BasicNetworking/.google/packaging.yaml b/prebuilts/gradle/BasicNetworking/.google/packaging.yaml index 57f27960..6f178e2d 100644 --- a/prebuilts/gradle/BasicNetworking/.google/packaging.yaml +++ b/prebuilts/gradle/BasicNetworking/.google/packaging.yaml @@ -9,4 +9,9 @@ categories: [Connectivity] languages: [Java] solutions: [Mobile] github: android-BasicNetworking +level: INTERMEDIATE +icon: screenshots/big_icon.png +apiRefs: + - android:android.net.ConnectivityManager + - android:android.net.NetworkInfo license: apache2 diff --git a/prebuilts/gradle/BasicNetworking/Application/build.gradle b/prebuilts/gradle/BasicNetworking/Application/build.gradle index 05020be5..76169dee 100644 --- a/prebuilts/gradle/BasicNetworking/Application/build.gradle +++ b/prebuilts/gradle/BasicNetworking/Application/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" + compile "com.android.support:support-v4:21.0.2" } diff --git a/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-hdpi/ic_launcher.png b/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-hdpi/ic_launcher.png Binary files differindex 22ce6061..fad6812b 100755 --- a/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-hdpi/ic_launcher.png +++ b/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-mdpi/ic_launcher.png b/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-mdpi/ic_launcher.png Binary files differindex f21e17b6..04cf1152 100755 --- a/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-mdpi/ic_launcher.png +++ b/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differindex 64b80590..53736dfe 100755 --- a/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-xhdpi/ic_launcher.png +++ b/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-xxhdpi/ic_launcher.png Binary files differindex 6b4434a8..6afbfca3 100755 --- a/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-xxhdpi/ic_launcher.png +++ b/prebuilts/gradle/BasicNetworking/Application/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/prebuilts/gradle/BasicNetworking/Application/src/main/res/values/base-strings.xml b/prebuilts/gradle/BasicNetworking/Application/src/main/res/values/base-strings.xml index 9a86c89d..ddd695f9 100644 --- a/prebuilts/gradle/BasicNetworking/Application/src/main/res/values/base-strings.xml +++ b/prebuilts/gradle/BasicNetworking/Application/src/main/res/values/base-strings.xml @@ -20,10 +20,10 @@ <![CDATA[ - This sample demonstrates how to use the ConnectivityManager to determine if you have - a network connection, and if so, what type of connection it is. - \n\nA "NetworkInfo" object is retrieved from the ConnectivityManager, which contains information - on the active connection, and then the connection type is printed to an on-screen console. + This sample demonstrates how to use the ConnectivityManager to determine if you have + a network connection, and if so, what type of connection it is. + \n\nA "NetworkInfo" object is retrieved from the ConnectivityManager, which contains information + on the active connection, and then the connection type is printed to an on-screen console. ]]> diff --git a/prebuilts/gradle/BasicNetworking/README.md b/prebuilts/gradle/BasicNetworking/README.md index 9a5eeadc..25a04cef 100644 --- a/prebuilts/gradle/BasicNetworking/README.md +++ b/prebuilts/gradle/BasicNetworking/README.md @@ -1,12 +1,23 @@ Android BasicNetworking Sample =================================== -This sample demonstrates how to use the ConnectivityManager to determine if you have +This sample demonstrates how to check network connectivity with Android APIs. + +Introduction +------------ + +It utilizes the [`ConnectivityManager`][1] to determine if you have a network connection, and if so, what type of connection it is. -A "NetworkInfo" object is retrieved from the ConnectivityManager, which contains information +A [`NetworkInfo`][2] object is retrieved from the ConnectivityManager, which contains information on the active connection, and then the connection type is printed to an on-screen console. +Multiple types of connectivity can be displayed and could be used to take different measures +in actual production code. + +[1]: https://developer.android.com/reference/android/net/ConnectivityManager.html +[2]: https://developer.android.com/reference/android/net/NetworkInfo.html + Pre-requisites -------------- @@ -14,6 +25,11 @@ Pre-requisites - Android Build Tools v21.1.1 - Android Support Repository +Screenshots +------------- + +<img src="screenshots/start.png" height="400" alt="Screenshot"/> <img src="screenshots/tested.png" height="400" alt="Screenshot"/> + Getting Started --------------- diff --git a/prebuilts/gradle/BasicNetworking/screenshots/big_icon.png b/prebuilts/gradle/BasicNetworking/screenshots/big_icon.png Binary files differnew file mode 100644 index 00000000..a9c88499 --- /dev/null +++ b/prebuilts/gradle/BasicNetworking/screenshots/big_icon.png diff --git a/prebuilts/gradle/BasicNetworking/screenshots/start.png b/prebuilts/gradle/BasicNetworking/screenshots/start.png Binary files differnew file mode 100644 index 00000000..e244f189 --- /dev/null +++ b/prebuilts/gradle/BasicNetworking/screenshots/start.png diff --git a/prebuilts/gradle/BasicNetworking/screenshots/tested.png b/prebuilts/gradle/BasicNetworking/screenshots/tested.png Binary files differnew file mode 100644 index 00000000..96359c6b --- /dev/null +++ b/prebuilts/gradle/BasicNetworking/screenshots/tested.png diff --git a/prebuilts/gradle/BasicNotifications/Application/build.gradle b/prebuilts/gradle/BasicNotifications/Application/build.gradle index 90737fcc..3e25a83b 100644 --- a/prebuilts/gradle/BasicNotifications/Application/build.gradle +++ b/prebuilts/gradle/BasicNotifications/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BasicRenderScript/Application/build.gradle b/prebuilts/gradle/BasicRenderScript/Application/build.gradle index 641b05e5..23a18632 100644 --- a/prebuilts/gradle/BasicRenderScript/Application/build.gradle +++ b/prebuilts/gradle/BasicRenderScript/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" compile files('renderscript-v8.jar') } diff --git a/prebuilts/gradle/BasicSyncAdapter/.google/packaging.yaml b/prebuilts/gradle/BasicSyncAdapter/.google/packaging.yaml index cead24a9..9d07bf6c 100644 --- a/prebuilts/gradle/BasicSyncAdapter/.google/packaging.yaml +++ b/prebuilts/gradle/BasicSyncAdapter/.google/packaging.yaml @@ -5,8 +5,17 @@ --- status: PUBLISHED technologies: [Android] -categories: [Connectivity] +categories: [Background, Connectivity] languages: [Java] solutions: [Mobile] github: android-BasicSyncAdapter +level: INTERMEDIATE +icon: screenshots/icon-web.png +apiRefs: + - android:android.app.Service + - android:android.content.AbstractThreadedSyncAdapter + - android:android.content.ContentProvider + - android:android.content.ContentResolver + - android:android.content.SyncResult + - android:android.database.sqlite.SQLiteDatabase license: apache2 diff --git a/prebuilts/gradle/BasicSyncAdapter/Application/build.gradle b/prebuilts/gradle/BasicSyncAdapter/Application/build.gradle index c5134fb4..292c2d14 100644 --- a/prebuilts/gradle/BasicSyncAdapter/Application/build.gradle +++ b/prebuilts/gradle/BasicSyncAdapter/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-hdpi/ic_launcher.png b/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-hdpi/ic_launcher.png Binary files differindex a0f7005a..7920c98e 100644 --- a/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-hdpi/ic_launcher.png +++ b/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-mdpi/ic_launcher.png b/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-mdpi/ic_launcher.png Binary files differindex a085462c..1de60fe4 100644 --- a/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-mdpi/ic_launcher.png +++ b/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differindex 4f78eb84..fc4bfebd 100644 --- a/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-xhdpi/ic_launcher.png +++ b/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-xxhdpi/ic_launcher.png Binary files differindex b198ee3e..646ce941 100644 --- a/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-xxhdpi/ic_launcher.png +++ b/prebuilts/gradle/BasicSyncAdapter/Application/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/prebuilts/gradle/BasicSyncAdapter/README.md b/prebuilts/gradle/BasicSyncAdapter/README.md index fc21471e..c4900092 100644 --- a/prebuilts/gradle/BasicSyncAdapter/README.md +++ b/prebuilts/gradle/BasicSyncAdapter/README.md @@ -1,13 +1,28 @@ Android BasicSyncAdapter Sample =================================== -This sample demonstrates using SyncAdapter to fetch background data for an app that -doesn't require a user-visible account type or 2-way synchronization. +This sample demonstrates using SyncAdapter to fetch background +data for an app. It covers the creation of the required Service +that the OS uses to initiate the background data sync as well as +scheduling syncs with background data. +Introduction +------------ -This sample periodically downloads the feed from the Android Developer Blog and -caches the data in a content provider. At runtime, the cached feed data is displayed -inside a ListView. +This sample demonstrates using SyncAdapter to fetch background data +for an app. SyncAdapters can be used to execute your data transfer +code at configurable intervals, while efficiently using battery and +other system resources. + +This sample implements all the required elements of a sync adapter. +- Creates a sync adapter class. +- Creates a bound Service which the OS uses to initiate a sync. +- Defines the sync adapter properties in an XML resource file. +- Declares the bound Service in the app manifest. + +For more on SyncAdapters refer to [Transferring Data Using Sync Adapters][1] + +[1]: http://developer.android.com/training/sync-adapters/index.html Pre-requisites -------------- @@ -16,6 +31,11 @@ Pre-requisites - Android Build Tools v21.1.1 - Android Support Repository +Screenshots +------------- + +<img src="screenshots/main.png" height="400" alt="Screenshot"/> + Getting Started --------------- diff --git a/prebuilts/gradle/BasicSyncAdapter/screenshots/icon-web.png b/prebuilts/gradle/BasicSyncAdapter/screenshots/icon-web.png Binary files differnew file mode 100644 index 00000000..7904a13a --- /dev/null +++ b/prebuilts/gradle/BasicSyncAdapter/screenshots/icon-web.png diff --git a/prebuilts/gradle/BasicSyncAdapter/screenshots/main.png b/prebuilts/gradle/BasicSyncAdapter/screenshots/main.png Binary files differnew file mode 100644 index 00000000..c0a9d483 --- /dev/null +++ b/prebuilts/gradle/BasicSyncAdapter/screenshots/main.png diff --git a/prebuilts/gradle/BasicTransition/Application/build.gradle b/prebuilts/gradle/BasicTransition/Application/build.gradle index bfed04fa..c6b8c26a 100644 --- a/prebuilts/gradle/BasicTransition/Application/build.gradle +++ b/prebuilts/gradle/BasicTransition/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BatchStepSensor/Application/build.gradle b/prebuilts/gradle/BatchStepSensor/Application/build.gradle index bfed04fa..c6b8c26a 100644 --- a/prebuilts/gradle/BatchStepSensor/Application/build.gradle +++ b/prebuilts/gradle/BatchStepSensor/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BluetoothChat/Application/build.gradle b/prebuilts/gradle/BluetoothChat/Application/build.gradle index 8380768f..8b72299a 100644 --- a/prebuilts/gradle/BluetoothChat/Application/build.gradle +++ b/prebuilts/gradle/BluetoothChat/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BluetoothLeGatt/Application/build.gradle b/prebuilts/gradle/BluetoothLeGatt/Application/build.gradle index f3cacbe1..3859b3ee 100644 --- a/prebuilts/gradle/BluetoothLeGatt/Application/build.gradle +++ b/prebuilts/gradle/BluetoothLeGatt/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/BorderlessButtons/Application/build.gradle b/prebuilts/gradle/BorderlessButtons/Application/build.gradle index 0427861a..37884d80 100644 --- a/prebuilts/gradle/BorderlessButtons/Application/build.gradle +++ b/prebuilts/gradle/BorderlessButtons/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/Camera2Basic/Application/build.gradle b/prebuilts/gradle/Camera2Basic/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/Camera2Basic/Application/build.gradle +++ b/prebuilts/gradle/Camera2Basic/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/Camera2Video/Application/build.gradle b/prebuilts/gradle/Camera2Video/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/Camera2Video/Application/build.gradle +++ b/prebuilts/gradle/Camera2Video/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/CardEmulation/Application/build.gradle b/prebuilts/gradle/CardEmulation/Application/build.gradle index bfed04fa..c6b8c26a 100644 --- a/prebuilts/gradle/CardEmulation/Application/build.gradle +++ b/prebuilts/gradle/CardEmulation/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/CardReader/Application/build.gradle b/prebuilts/gradle/CardReader/Application/build.gradle index bfed04fa..c6b8c26a 100644 --- a/prebuilts/gradle/CardReader/Application/build.gradle +++ b/prebuilts/gradle/CardReader/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/CardView/Application/build.gradle b/prebuilts/gradle/CardView/Application/build.gradle index 53483bad..13964de1 100644 --- a/prebuilts/gradle/CardView/Application/build.gradle +++ b/prebuilts/gradle/CardView/Application/build.gradle @@ -18,7 +18,7 @@ repositories { dependencies { - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:cardview-v7:21.0.2" } // The sample build uses multiple directories to diff --git a/prebuilts/gradle/ClippingBasic/Application/build.gradle b/prebuilts/gradle/ClippingBasic/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/ClippingBasic/Application/build.gradle +++ b/prebuilts/gradle/ClippingBasic/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/CustomChoiceList/Application/build.gradle b/prebuilts/gradle/CustomChoiceList/Application/build.gradle index 05020be5..76169dee 100644 --- a/prebuilts/gradle/CustomChoiceList/Application/build.gradle +++ b/prebuilts/gradle/CustomChoiceList/Application/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" + compile "com.android.support:support-v4:21.0.2" } diff --git a/prebuilts/gradle/CustomNotifications/Application/build.gradle b/prebuilts/gradle/CustomNotifications/Application/build.gradle index 05020be5..76169dee 100644 --- a/prebuilts/gradle/CustomNotifications/Application/build.gradle +++ b/prebuilts/gradle/CustomNotifications/Application/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" + compile "com.android.support:support-v4:21.0.2" } diff --git a/prebuilts/gradle/CustomTransition/Application/build.gradle b/prebuilts/gradle/CustomTransition/Application/build.gradle index bfed04fa..c6b8c26a 100644 --- a/prebuilts/gradle/CustomTransition/Application/build.gradle +++ b/prebuilts/gradle/CustomTransition/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/DirectorySelection/.google/packaging.yaml b/prebuilts/gradle/DirectorySelection/.google/packaging.yaml new file mode 100644 index 00000000..a750a88d --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/.google/packaging.yaml @@ -0,0 +1,17 @@ +# GOOGLE SAMPLE PACKAGING DATA +# +# This file is used by Google as part of our samples packaging process. +# End users may safely ignore this file. It has no relevance to other systems. +--- +status: DRAFTED +technologies: [Android] +categories: [Content] +languages: [Java] +solutions: [Mobile] +github: android-DirectorySelection +level: INTERMEDIATE +icon: screenshots/web-icon.png +apiRefs: + - android:android.content.ContentResolver + - android:android.provider.DocumentsContract +license: apache2 diff --git a/prebuilts/gradle/DirectorySelection/Application/build.gradle b/prebuilts/gradle/DirectorySelection/Application/build.gradle new file mode 100644 index 00000000..6bd132fb --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/build.gradle @@ -0,0 +1,71 @@ +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:1.0.0' + } +} + +apply plugin: 'com.android.application' + +repositories { + jcenter() +} + + +dependencies { + + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" + + compile "com.android.support:recyclerview-v7:+" +} + +// The sample build uses multiple directories to +// keep boilerplate and common code separate from +// the main sample code. +List<String> dirs = [ + 'main', // main sample code; look here for the interesting stuff. + 'common', // components that are reused by multiple samples + 'template'] // boilerplate code that is generated by the sample template process + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 21 + targetSdkVersion 21 + } + + sourceSets { + main { + dirs.each { dir -> + java.srcDirs "src/${dir}/java" + res.srcDirs "src/${dir}/res" + } + } + androidTest.setRoot('tests') + androidTest.java.srcDirs = ['tests/src'] + + } + +} + + + + + + + + + + + + + + + diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/AndroidManifest.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/AndroidManifest.xml new file mode 100644 index 00000000..46cddcfa --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/AndroidManifest.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.directoryselection" + android:versionCode="1" + android:versionName="1.0"> + + <application android:allowBackup="true" + android:label="@string/app_name" + android:icon="@drawable/ic_launcher" + android:theme="@style/AppTheme"> + + <activity android:name=".DirectorySelectionActivity" + 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/prebuilts/gradle/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectoryEntry.java b/prebuilts/gradle/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectoryEntry.java new file mode 100644 index 00000000..04c1c896 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectoryEntry.java @@ -0,0 +1,25 @@ +/* +* 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.directoryselection; + +/** + * Entity class that represents an directory entry. + */ +public class DirectoryEntry { + public String fileName; + public String mimeType; +} diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectoryEntryAdapter.java b/prebuilts/gradle/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectoryEntryAdapter.java new file mode 100644 index 00000000..e92c71ec --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectoryEntryAdapter.java @@ -0,0 +1,100 @@ +/* +* 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.directoryselection; + +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.util.List; + +/** + * Provide views to RecyclerView with the directory entries. + */ +public class DirectoryEntryAdapter extends RecyclerView.Adapter<DirectoryEntryAdapter.ViewHolder> { + + static final String DIRECTORY_MIME_TYPE = "vnd.android.document/directory"; + private List<DirectoryEntry> mDirectoryEntries; + + /** + * Provide a reference to the type of views that you are using (custom ViewHolder) + */ + public static class ViewHolder extends RecyclerView.ViewHolder { + private final TextView mFileName; + private final TextView mMimeType; + private final ImageView mImageView; + + public ViewHolder(View v) { + super(v); + mFileName = (TextView) v.findViewById(R.id.textview_filename); + mMimeType = (TextView) v.findViewById(R.id.textview_mimetype); + mImageView = (ImageView) v.findViewById(R.id.entry_image); + } + + public TextView getFileName() { + return mFileName; + } + + public TextView getMimeType() { + return mMimeType; + } + + public ImageView getImageView() { + return mImageView; + } + } + + /** + * Initialize the directory entries of the Adapter. + * + * @param directoryEntries an array of {@link DirectoryEntry}. + */ + public DirectoryEntryAdapter(List<DirectoryEntry> directoryEntries) { + mDirectoryEntries = directoryEntries; + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { + View v = LayoutInflater.from(viewGroup.getContext()) + .inflate(R.layout.directory_item, viewGroup, false); + return new ViewHolder(v); + } + + @Override + public void onBindViewHolder(ViewHolder viewHolder, final int position) { + viewHolder.getFileName().setText(mDirectoryEntries.get(position).fileName); + viewHolder.getMimeType().setText(mDirectoryEntries.get(position).mimeType); + + if (DIRECTORY_MIME_TYPE.equals(mDirectoryEntries.get(position).mimeType)) { + viewHolder.getImageView().setImageResource(R.drawable.ic_folder_grey600_36dp); + } else { + viewHolder.getImageView().setImageResource(R.drawable.ic_description_grey600_36dp); + } + } + + @Override + public int getItemCount() { + return mDirectoryEntries.size(); + } + + public void setDirectoryEntries(List<DirectoryEntry> directoryEntries) { + mDirectoryEntries = directoryEntries; + } +} diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectorySelectionActivity.java b/prebuilts/gradle/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectorySelectionActivity.java new file mode 100644 index 00000000..d27ba728 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectorySelectionActivity.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.directoryselection; + +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; + +/** + * Launcher Activity for the Directory Selection sample app. + */ +public class DirectorySelectionActivity extends FragmentActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_directory_selection); + if (savedInstanceState == null) { + getSupportFragmentManager().beginTransaction() + .add(R.id.container, DirectorySelectionFragment.newInstance()) + .commit(); + } + } +} diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectorySelectionFragment.java b/prebuilts/gradle/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectorySelectionFragment.java new file mode 100644 index 00000000..4af55dbe --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectorySelectionFragment.java @@ -0,0 +1,231 @@ +/* +* 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.directoryselection; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.ContentResolver; +import android.content.DialogInterface; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.provider.DocumentsContract; +import android.provider.DocumentsContract.Document; +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.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.List; + +/** + * Fragment that demonstrates how to use Directory Selection API. + */ +public class DirectorySelectionFragment extends Fragment { + + private static final String TAG = DirectorySelectionFragment.class.getSimpleName(); + + public static final int REQUEST_CODE_OPEN_DIRECTORY = 1; + + Uri mCurrentDirectoryUri; + TextView mCurrentDirectoryTextView; + Button mCreateDirectoryButton; + RecyclerView mRecyclerView; + DirectoryEntryAdapter mAdapter; + RecyclerView.LayoutManager mLayoutManager; + + /** + * Use this factory method to create a new instance of + * this fragment using the provided parameters. + * + * @return A new instance of fragment {@link DirectorySelectionFragment}. + */ + public static DirectorySelectionFragment newInstance() { + DirectorySelectionFragment fragment = new DirectorySelectionFragment(); + return fragment; + } + + public DirectorySelectionFragment() { + // Required empty public constructor + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_directory_selection, container, false); + } + + @Override + public void onViewCreated(View rootView, Bundle savedInstanceState) { + super.onViewCreated(rootView, savedInstanceState); + + rootView.findViewById(R.id.button_open_directory) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); + startActivityForResult(intent, REQUEST_CODE_OPEN_DIRECTORY); + } + }); + + mCurrentDirectoryTextView = (TextView) rootView + .findViewById(R.id.textview_current_directory); + mCreateDirectoryButton = (Button) rootView.findViewById(R.id.button_create_directory); + mCreateDirectoryButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + final EditText editView = new EditText(getActivity()); + new AlertDialog.Builder(getActivity()) + .setTitle(R.string.create_directory) + .setView(editView) + .setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + createDirectory(mCurrentDirectoryUri, + editView.getText().toString()); + updateDirectoryEntries(mCurrentDirectoryUri); + } + }) + .setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + } + }) + .show(); + } + }); + mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerview_directory_entries); + mLayoutManager = new LinearLayoutManager(getActivity()); + mRecyclerView.setLayoutManager(mLayoutManager); + mRecyclerView.scrollToPosition(0); + mAdapter = new DirectoryEntryAdapter(new ArrayList<DirectoryEntry>()); + mRecyclerView.setAdapter(mAdapter); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == REQUEST_CODE_OPEN_DIRECTORY && resultCode == Activity.RESULT_OK) { + Log.d(TAG, String.format("Open Directory result Uri : %s", data.getData())); + updateDirectoryEntries(data.getData()); + mAdapter.notifyDataSetChanged(); + } + } + + + /** + * Updates the current directory of the uri passed as an argument and its children directories. + * And updates the {@link #mRecyclerView} depending on the contents of the children. + * + * @param uri The uri of the current directory. + */ + //VisibileForTesting + void updateDirectoryEntries(Uri uri) { + ContentResolver contentResolver = getActivity().getContentResolver(); + Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri, + DocumentsContract.getTreeDocumentId(uri)); + Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(uri, + DocumentsContract.getTreeDocumentId(uri)); + + Cursor docCursor = contentResolver.query(docUri, new String[]{ + Document.COLUMN_DISPLAY_NAME, Document.COLUMN_MIME_TYPE}, null, null, null); + try { + while (docCursor.moveToNext()) { + Log.d(TAG, "found doc =" + docCursor.getString(0) + ", mime=" + docCursor + .getString(1)); + mCurrentDirectoryUri = uri; + mCurrentDirectoryTextView.setText(docCursor.getString(0)); + mCreateDirectoryButton.setEnabled(true); + } + } finally { + closeQuietly(docCursor); + } + + Cursor childCursor = contentResolver.query(childrenUri, new String[]{ + Document.COLUMN_DISPLAY_NAME, Document.COLUMN_MIME_TYPE}, null, null, null); + try { + List<DirectoryEntry> directoryEntries = new ArrayList<>(); + while (childCursor.moveToNext()) { + Log.d(TAG, "found child=" + childCursor.getString(0) + ", mime=" + childCursor + .getString(1)); + DirectoryEntry entry = new DirectoryEntry(); + entry.fileName = childCursor.getString(0); + entry.mimeType = childCursor.getString(1); + directoryEntries.add(entry); + } + mAdapter.setDirectoryEntries(directoryEntries); + mAdapter.notifyDataSetChanged(); + } finally { + closeQuietly(childCursor); + } + } + + /** + * Creates a directory under the directory represented as the uri in the argument. + * + * @param uri The uri of the directory under which a new directory is created. + * @param directoryName The directory name of a new directory. + */ + //VisibileForTesting + void createDirectory(Uri uri, String directoryName) { + ContentResolver contentResolver = getActivity().getContentResolver(); + Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri, + DocumentsContract.getTreeDocumentId(uri)); + Uri directoryUri = DocumentsContract + .createDocument(contentResolver, docUri, Document.MIME_TYPE_DIR, directoryName); + if (directoryUri != null) { + Log.i(TAG, String.format( + "Created directory : %s, Document Uri : %s, Created directory Uri : %s", + directoryName, docUri, directoryUri)); + Toast.makeText(getActivity(), String.format("Created a directory [%s]", + directoryName), Toast.LENGTH_SHORT).show(); + } else { + Log.w(TAG, String.format("Failed to create a directory : %s, Uri %s", directoryName, + docUri)); + Toast.makeText(getActivity(), String.format("Failed to created a directory [%s] : ", + directoryName), Toast.LENGTH_SHORT).show(); + } + + } + + public void closeQuietly(AutoCloseable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) { + } + } + } +} + diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-hdpi/ic_description_grey600_36dp.png b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-hdpi/ic_description_grey600_36dp.png Binary files differnew file mode 100755 index 00000000..dd7d0734 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-hdpi/ic_description_grey600_36dp.png diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-hdpi/ic_folder_grey600_36dp.png b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-hdpi/ic_folder_grey600_36dp.png Binary files differnew file mode 100755 index 00000000..6c022d46 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-hdpi/ic_folder_grey600_36dp.png diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-hdpi/ic_launcher.png b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100755 index 00000000..49ee8546 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-hdpi/tile.9.png b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-hdpi/tile.9.png Binary files differnew file mode 100644 index 00000000..13586288 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-hdpi/tile.9.png diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-mdpi/ic_description_grey600_36dp.png b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-mdpi/ic_description_grey600_36dp.png Binary files differnew file mode 100755 index 00000000..ac18b575 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-mdpi/ic_description_grey600_36dp.png diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-mdpi/ic_folder_grey600_36dp.png b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-mdpi/ic_folder_grey600_36dp.png Binary files differnew file mode 100755 index 00000000..e3dccd29 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-mdpi/ic_folder_grey600_36dp.png diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-mdpi/ic_launcher.png b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100755 index 00000000..282a00c7 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xhdpi/ic_description_grey600_36dp.png b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xhdpi/ic_description_grey600_36dp.png Binary files differnew file mode 100755 index 00000000..50f854ea --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xhdpi/ic_description_grey600_36dp.png diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xhdpi/ic_folder_grey600_36dp.png b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xhdpi/ic_folder_grey600_36dp.png Binary files differnew file mode 100755 index 00000000..6fbc4045 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xhdpi/ic_folder_grey600_36dp.png diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100755 index 00000000..7293ad6e --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xxhdpi/ic_description_grey600_36dp.png b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xxhdpi/ic_description_grey600_36dp.png Binary files differnew file mode 100755 index 00000000..33df5d9d --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xxhdpi/ic_description_grey600_36dp.png diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xxhdpi/ic_folder_grey600_36dp.png b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xxhdpi/ic_folder_grey600_36dp.png Binary files differnew file mode 100755 index 00000000..ed2f08e4 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xxhdpi/ic_folder_grey600_36dp.png diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100755 index 00000000..7b618d40 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/layout/activity_directory_selection.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/layout/activity_directory_selection.xml new file mode 100644 index 00000000..db655838 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/layout/activity_directory_selection.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.directoryselection.DirectorySelectionActivity" + tools:ignore="MergeRootFrame" />
\ No newline at end of file diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/layout/activity_main.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/layout/activity_main.xml new file mode 100755 index 00000000..be1aa49d --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/layout/activity_main.xml @@ -0,0 +1,36 @@ +<!-- + 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. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <LinearLayout style="@style/Widget.SampleMessageTile" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView style="@style/Widget.SampleMessage" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/horizontal_page_margin" + android:layout_marginRight="@dimen/horizontal_page_margin" + android:layout_marginTop="@dimen/vertical_page_margin" + android:layout_marginBottom="@dimen/vertical_page_margin" + android:text="@string/intro_message" /> + </LinearLayout> +</LinearLayout> diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/layout/directory_item.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/layout/directory_item.xml new file mode 100644 index 00000000..0763cff6 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/layout/directory_item.xml @@ -0,0 +1,57 @@ +<?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/directory_item_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/entry_image" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_folder_grey600_36dp" + /> + <LinearLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/margin_medium" + android:orientation="vertical" + > + <View android:id="@+id/divisor" + android:layout_width="match_parent" + android:layout_height="1dp" + android:background="#aaaaaa"/> + + <TextView + android:id="@+id/textview_filename" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/DirectoryEntryNameFont" + /> + <TextView + android:id="@+id/textview_mimetype" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + </LinearLayout> + </LinearLayout> +</RelativeLayout> diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/layout/fragment_directory_selection.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/layout/fragment_directory_selection.xml new file mode 100644 index 00000000..d63219c5 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/layout/fragment_directory_selection.xml @@ -0,0 +1,74 @@ +<?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"> + + <LinearLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + > + + <Button android:id="@+id/button_open_directory" + android:text="@string/open_directory" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <Button android:id="@+id/button_create_directory" + android:text="@string/create_directory" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:enabled="false" + /> + </LinearLayout> + + <LinearLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_marginLeft="@dimen/margin_small" + android:layout_marginRight="@dimen/margin_small" + > + + <TextView android:id="@+id/label_current_directory" + android:text="@string/selected_directory" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <TextView android:id="@+id/textview_current_directory" + android:enabled="false" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/DirectoryEntryNameFont" + /> + + </LinearLayout> + + <android.support.v7.widget.RecyclerView + android:id="@+id/recyclerview_directory_entries" + 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/prebuilts/gradle/DirectorySelection/Application/src/main/res/menu/main.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/menu/main.xml new file mode 100644 index 00000000..e9b5e0b1 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/menu/main.xml @@ -0,0 +1,16 @@ +<!-- + 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. + --> +<menu xmlns:android="http://schemas.android.com/apk/res/android" /> diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-sw600dp/template-dimens.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-sw600dp/template-dimens.xml new file mode 100644 index 00000000..22074a2b --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-sw600dp/template-dimens.xml @@ -0,0 +1,24 @@ +<!-- + 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. + --> + +<resources> + + <!-- Semantic definitions --> + + <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen> + <dimen name="vertical_page_margin">@dimen/margin_medium</dimen> + +</resources> diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-sw600dp/template-styles.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-sw600dp/template-styles.xml new file mode 100644 index 00000000..03d19741 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-sw600dp/template-styles.xml @@ -0,0 +1,25 @@ +<!-- + 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. + --> + +<resources> + + <style name="Widget.SampleMessage"> + <item name="android:textAppearance">?android:textAppearanceLarge</item> + <item name="android:lineSpacingMultiplier">1.2</item> + <item name="android:shadowDy">-6.5</item> + </style> + +</resources> diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-v11/template-styles.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-v11/template-styles.xml new file mode 100644 index 00000000..8c1ea66f --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-v11/template-styles.xml @@ -0,0 +1,22 @@ +<!-- + 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. + --> + +<resources> + + <!-- Activity themes --> + <style name="Theme.Base" parent="android:Theme.Holo.Light" /> + +</resources> diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-v21/base-colors.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-v21/base-colors.xml new file mode 100644 index 00000000..34c9cd13 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-v21/base-colors.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<resources> + + +</resources> diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-v21/base-template-styles.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-v21/base-template-styles.xml new file mode 100644 index 00000000..0b2948f7 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values-v21/base-template-styles.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<resources> + + <!-- Activity themes --> + <style name="Theme.Base" parent="android:Theme.Material.Light"> + </style> + +</resources> diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/base-strings.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/base-strings.xml new file mode 100644 index 00000000..782c64aa --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/base-strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<resources> + <string name="app_name">DirectorySelection</string> + <string name="intro_message"> + <![CDATA[ + + + This sample explains how to use Directory selection API, which was introduced + in Android 5.0. + + + ]]> + </string> +</resources> diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/dimens.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/dimens.xml new file mode 100644 index 00000000..53d0182c --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/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="directory_item_height">72dp</dimen> +</resources>
\ No newline at end of file diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/strings.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/strings.xml new file mode 100644 index 00000000..24d59dde --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/strings.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> + <string name="open_directory">Open directory</string> + <string name="create_directory">Create Directory</string> + <string name="selected_directory">"Selected Directory : "</string> +</resources> diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/styles.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/styles.xml new file mode 100644 index 00000000..38441f38 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/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="DirectoryEntryNameFont" parent="@android:style/TextAppearance.Medium"> + <item name="android:textColor">#000000</item> + </style> +</resources>
\ No newline at end of file diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/template-dimens.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/template-dimens.xml new file mode 100644 index 00000000..39e710b5 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/template-dimens.xml @@ -0,0 +1,32 @@ +<!-- + 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. + --> + +<resources> + + <!-- Define standard dimensions to comply with Holo-style grids and rhythm. --> + + <dimen name="margin_tiny">4dp</dimen> + <dimen name="margin_small">8dp</dimen> + <dimen name="margin_medium">16dp</dimen> + <dimen name="margin_large">32dp</dimen> + <dimen name="margin_huge">64dp</dimen> + + <!-- Semantic definitions --> + + <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen> + <dimen name="vertical_page_margin">@dimen/margin_medium</dimen> + +</resources> diff --git a/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/template-styles.xml b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/template-styles.xml new file mode 100644 index 00000000..6e7d593d --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/src/main/res/values/template-styles.xml @@ -0,0 +1,42 @@ +<!-- + 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. + --> + +<resources> + + <!-- Activity themes --> + + <style name="Theme.Base" parent="android:Theme.Light" /> + + <style name="Theme.Sample" parent="Theme.Base" /> + + <style name="AppTheme" parent="Theme.Sample" /> + <!-- Widget styling --> + + <style name="Widget" /> + + <style name="Widget.SampleMessage"> + <item name="android:textAppearance">?android:textAppearanceMedium</item> + <item name="android:lineSpacingMultiplier">1.1</item> + </style> + + <style name="Widget.SampleMessageTile"> + <item name="android:background">@drawable/tile</item> + <item name="android:shadowColor">#7F000000</item> + <item name="android:shadowDy">-3.5</item> + <item name="android:shadowRadius">2</item> + </style> + +</resources> diff --git a/prebuilts/gradle/DirectorySelection/Application/tests/src/com/example/android/directoryselection/DirectoryEntryAdapterTest.java b/prebuilts/gradle/DirectorySelection/Application/tests/src/com/example/android/directoryselection/DirectoryEntryAdapterTest.java new file mode 100644 index 00000000..97b26293 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/tests/src/com/example/android/directoryselection/DirectoryEntryAdapterTest.java @@ -0,0 +1,82 @@ +/* +* 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.directoryselection; + +import android.test.ActivityInstrumentationTestCase2; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tests for {@link DirectorySelectionFragment}. + */ +public class DirectoryEntryAdapterTest + extends ActivityInstrumentationTestCase2<DirectorySelectionActivity> { + + private static final String FILE1 = "file1"; + private static final String MIME_TYPE1 = "text/appliaction"; + private static final String DIRECTORY1 = "directory1"; + + private DirectorySelectionActivity mTestActivity; + private DirectorySelectionFragment mTestFragment; + private DirectoryEntryAdapter mAdapter; + private List<DirectoryEntry> mDirectoryEntries; + + public DirectoryEntryAdapterTest() { + super(DirectorySelectionActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mTestActivity = getActivity(); + mTestFragment = (DirectorySelectionFragment) + mTestActivity.getSupportFragmentManager().getFragments().get(0); + mDirectoryEntries = new ArrayList<>(); + + DirectoryEntry file = new DirectoryEntry(); + file.fileName = FILE1; + file.mimeType = MIME_TYPE1; + mDirectoryEntries.add(file); + + DirectoryEntry directory = new DirectoryEntry(); + directory.fileName = DIRECTORY1; + directory.mimeType = DirectoryEntryAdapter.DIRECTORY_MIME_TYPE; + mDirectoryEntries.add(directory); + } + + public void testGetItemCount() { + mTestFragment.mAdapter.setDirectoryEntries(mDirectoryEntries); + + assertEquals(2, mTestFragment.mAdapter.getItemCount()); + } +} diff --git a/prebuilts/gradle/DirectorySelection/Application/tests/src/com/example/android/directoryselection/DirectorySelectionActivityTest.java b/prebuilts/gradle/DirectorySelection/Application/tests/src/com/example/android/directoryselection/DirectorySelectionActivityTest.java new file mode 100644 index 00000000..8f767aef --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/tests/src/com/example/android/directoryselection/DirectorySelectionActivityTest.java @@ -0,0 +1,56 @@ +/* +* 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.directoryselection; + +import android.test.ActivityInstrumentationTestCase2; + +/** + * Tests for {@link DirectorySelectionActivity}. + */ +public class DirectorySelectionActivityTest + extends ActivityInstrumentationTestCase2<DirectorySelectionActivity> { + + private DirectorySelectionActivity mTestActivity; + private DirectorySelectionFragment mTestFragment; + + public DirectorySelectionActivityTest() { + super(DirectorySelectionActivity.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 = (DirectorySelectionFragment) + 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/prebuilts/gradle/DirectorySelection/Application/tests/src/com/example/android/directoryselection/DirectorySelectionFragmentTest.java b/prebuilts/gradle/DirectorySelection/Application/tests/src/com/example/android/directoryselection/DirectorySelectionFragmentTest.java new file mode 100644 index 00000000..90cd30f7 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/Application/tests/src/com/example/android/directoryselection/DirectorySelectionFragmentTest.java @@ -0,0 +1,68 @@ +/* +* 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.directoryselection; + +import android.test.ActivityInstrumentationTestCase2; + +/** + * Tests for {@link com.example.android.directoryselection.DirectorySelectionFragment}. + */ +public class DirectorySelectionFragmentTest + extends ActivityInstrumentationTestCase2<DirectorySelectionActivity> { + + private DirectorySelectionActivity mTestActivity; + private DirectorySelectionFragment mTestFragment; + + public DirectorySelectionFragmentTest() { + super(DirectorySelectionActivity.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 = (DirectorySelectionFragment) + mTestActivity.getSupportFragmentManager().getFragments().get(0); + } + + public void testPreconditions() { + assertNotNull(mTestFragment.mCurrentDirectoryTextView); + assertNotNull(mTestFragment.mCreateDirectoryButton); + assertNotNull(mTestFragment.mRecyclerView); + assertNotNull(mTestFragment.mAdapter); + assertNotNull(mTestFragment.mLayoutManager); + } +} diff --git a/prebuilts/gradle/DirectorySelection/CONTRIBUTING.md b/prebuilts/gradle/DirectorySelection/CONTRIBUTING.md new file mode 100644 index 00000000..faa8b5c6 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/CONTRIBUTING.md @@ -0,0 +1,35 @@ +# How to become a contributor and submit your own code + +## Contributor License Agreements + +We'd love to accept your sample apps and patches! Before we can take them, we +have to jump a couple of legal hurdles. + +Please fill out either the individual or corporate Contributor License Agreement (CLA). + + * If you are an individual writing original source code and you're sure you + own the intellectual property, then you'll need to sign an [individual CLA] + (https://cla.developers.google.com). + * If you work for a company that wants to allow you to contribute your work, + then you'll need to sign a [corporate CLA] + (https://cla.developers.google.com). + +Follow either of the two links above to access the appropriate CLA and +instructions for how to sign and return it. Once we receive it, we'll be able to +accept your pull requests. + +## Contributing A Patch + +1. Submit an issue describing your proposed change to the repo in question. +1. The repo owner will respond to your issue promptly. +1. If your proposed change is accepted, and you haven't already done so, sign a + Contributor License Agreement (see details above). +1. Fork the desired repo, develop and test your code changes. +1. Ensure that your code adheres to the existing style in the sample to which + you are contributing. Refer to the + [Android Code Style Guide] + (https://source.android.com/source/code-style.html) for the + recommended coding standards for this organization. +1. Ensure that your code has an appropriate set of unit tests which all pass. +1. Submit a pull request. + diff --git a/prebuilts/gradle/DirectorySelection/LICENSE b/prebuilts/gradle/DirectorySelection/LICENSE new file mode 100644 index 00000000..1af981f5 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + 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. diff --git a/prebuilts/gradle/DirectorySelection/NOTICE b/prebuilts/gradle/DirectorySelection/NOTICE new file mode 100644 index 00000000..7eede3de --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/NOTICE @@ -0,0 +1,15 @@ +This sample uses the following software: + +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. diff --git a/prebuilts/gradle/DirectorySelection/README.md b/prebuilts/gradle/DirectorySelection/README.md new file mode 100644 index 00000000..1d3fb33c --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/README.md @@ -0,0 +1,154 @@ +Android DirectorySelection Sample +=================================== + +A basic app showing how to use Directory Selection API to let users +select an entire directory subtree, which extends the Storage Access Framework +introduced in Android 4.4 (API level 19). + +Introduction +------------ + +The [Directory Selection][1] API, which was introduced in Android 5.0 (API level 21) +extends the [Storage Access Framework][2] to let users select an entire directory subtree, +giving apps read/write access to all contained documents without requiring user +confirmation for each item. + +To select a directory subtree, build and send an [OPEN_DOCUMENT_TREE intent][3] like in the +following code: + +```java +Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); +startActivityForResult(intent, REQUEST_CODE_OPEN_DIRECTORY); +``` + +The system displays all [DocumentsProvider][4] instances that support subtree selection, + letting the user browse and select a directory. + +The returned URI represents access to the selected subtree. You can then use +[buildChildDocumentsUriUsingTree()][5] to access to the child documents and +[buildDocumentUriUsingTree()][6] to access to the selected directory itself along with [query()][7] +to explore the subtree. + +This example explores the child documents and the selected document by following code: + +```java +@Override +public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == REQUEST_CODE_OPEN_DIRECTORY && resultCode == Activity.RESULT_OK) { + updateDirectoryEntries(data.getData()); + } +} + +void updateDirectoryEntries(Uri uri) { + ContentResolver contentResolver = getActivity().getContentResolver(); + Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri, + DocumentsContract.getTreeDocumentId(uri)); + Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(uri, + DocumentsContract.getTreeDocumentId(uri)); + + Cursor docCursor = contentResolver.query(docUri, new String[]{ + Document.COLUMN_DISPLAY_NAME, Document.COLUMN_MIME_TYPE}, null, null, null); + try { + while (docCursor.moveToNext()) { + Log.d(TAG, "found doc =" + docCursor.getString(0) + ", mime=" + docCursor + .getString(1)); + mCurrentDirectoryUri = uri; + mCurrentDirectoryTextView.setText(docCursor.getString(0)); + mCreateDirectoryButton.setEnabled(true); + } + } finally { + closeQuietly(docCursor); + } + + Cursor childCursor = contentResolver.query(childrenUri, new String[]{ + Document.COLUMN_DISPLAY_NAME, Document.COLUMN_MIME_TYPE}, null, null, null); + try { + List<DirectoryEntry> directoryEntries = new ArrayList<>(); + while (childCursor.moveToNext()) { + Log.d(TAG, "found child=" + childCursor.getString(0) + ", mime=" + childCursor + .getString(1)); + DirectoryEntry entry = new DirectoryEntry(); + entry.fileName = childCursor.getString(0); + entry.mimeType = childCursor.getString(1); + directoryEntries.add(entry); + } + mAdapter.setDirectoryEntries(directoryEntries); + mAdapter.notifyDataSetChanged(); + } finally { + closeQuietly(childCursor); + } +} +``` + +Also, the new [createDocument()][8] method lets you create new documents or directories +anywhere under the subtree. + +This example creates a new directory by following code: + +```java +ContentResolver contentResolver = getActivity().getContentResolver(); +Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri, + DocumentsContract.getTreeDocumentId(uri)); +Uri directoryUri = DocumentsContract + .createDocument(contentResolver, docUri, Document.MIME_TYPE_DIR, directoryName); +``` + +[1]: https://developer.android.com/about/versions/android-5.0.html#Storage +[2]: https://developer.android.com/guide/topics/providers/document-provider.html +[3]: https://developer.android.com/reference/android/content/Intent.html#ACTION_OPEN_DOCUMENT_TREE +[4]: https://developer.android.com/reference/android/provider/DocumentsProvider.html +[5]: https://developer.android.com/reference/android/provider/DocumentsContract.html#buildChildDocumentsUriUsingTree(android.net.Uri%2C%20java.lang.String) +[6]: https://developer.android.com/reference/android/provider/DocumentsContract.html#buildDocumentUriUsingTree(android.net.Uri%2C%20java.lang.String) +[7]: https://developer.android.com/reference/android/content/ContentResolver.html#query(android.net.Uri%2C%20java.lang.String%5B%5D%2C%20java.lang.String%2C%20java.lang.String%5B%5D%2C%20java.lang.String) +[8]: https://developer.android.com/reference/android/provider/DocumentsContract.html#createDocument(android.content.ContentResolver%2C%20android.net.Uri%2C%20java.lang.String%2C%20java.lang.String) + +Pre-requisites +-------------- + +- Android SDK v21 +- Android Build Tools v21.1.1 +- Android Support Repository + +Screenshots +------------- + +<img src="screenshots/screenshot-1.png" height="400" alt="Screenshot"/> <img src="screenshots/screenshot-2.png" height="400" alt="Screenshot"/> <img src="screenshots/screenshot-3.png" height="400" alt="Screenshot"/> + +Getting Started +--------------- + +This sample uses the Gradle build system. To build this project, use the +"gradlew build" command or use "Import Project" in Android Studio. + +Support +------- + +- Google+ Community: https://plus.google.com/communities/105153134372062985968 +- Stack Overflow: http://stackoverflow.com/questions/tagged/android + +If you've found an error in this sample, please file an issue: +https://github.com/googlesamples/android-DirectorySelection + +Patches are encouraged, and may be submitted by forking this project and +submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details. + +License +------- + +Copyright 2014 The Android Open Source Project, Inc. + +Licensed to the Apache Software Foundation (ASF) under one or more contributor +license agreements. See the NOTICE file distributed with this work for +additional information regarding copyright ownership. The ASF licenses this +file to you 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. diff --git a/prebuilts/gradle/DirectorySelection/build.gradle b/prebuilts/gradle/DirectorySelection/build.gradle new file mode 100644 index 00000000..1dac6def --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/build.gradle @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/prebuilts/gradle/DirectorySelection/gradle/wrapper/gradle-wrapper.jar b/prebuilts/gradle/DirectorySelection/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 00000000..8c0fb64a --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/gradle/wrapper/gradle-wrapper.jar diff --git a/prebuilts/gradle/DirectorySelection/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/DirectorySelection/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..3e37868a --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Dec 03 14:12:05 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/prebuilts/gradle/DirectorySelection/gradlew b/prebuilts/gradle/DirectorySelection/gradlew new file mode 100755 index 00000000..91a7e269 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/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/prebuilts/gradle/DirectorySelection/gradlew.bat b/prebuilts/gradle/DirectorySelection/gradlew.bat new file mode 100644 index 00000000..aec99730 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/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/prebuilts/gradle/DirectorySelection/screenshots/screenshot-1.png b/prebuilts/gradle/DirectorySelection/screenshots/screenshot-1.png Binary files differnew file mode 100644 index 00000000..a4310dc7 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/screenshots/screenshot-1.png diff --git a/prebuilts/gradle/DirectorySelection/screenshots/screenshot-2.png b/prebuilts/gradle/DirectorySelection/screenshots/screenshot-2.png Binary files differnew file mode 100644 index 00000000..cd275075 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/screenshots/screenshot-2.png diff --git a/prebuilts/gradle/DirectorySelection/screenshots/screenshot-3.png b/prebuilts/gradle/DirectorySelection/screenshots/screenshot-3.png Binary files differnew file mode 100644 index 00000000..07954754 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/screenshots/screenshot-3.png diff --git a/prebuilts/gradle/DirectorySelection/screenshots/web-icon.png b/prebuilts/gradle/DirectorySelection/screenshots/web-icon.png Binary files differnew file mode 100755 index 00000000..f0a573f6 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/screenshots/web-icon.png diff --git a/prebuilts/gradle/DirectorySelection/settings.gradle b/prebuilts/gradle/DirectorySelection/settings.gradle new file mode 100644 index 00000000..9464a359 --- /dev/null +++ b/prebuilts/gradle/DirectorySelection/settings.gradle @@ -0,0 +1 @@ +include 'Application' diff --git a/prebuilts/gradle/DisplayingBitmaps/Application/build.gradle b/prebuilts/gradle/DisplayingBitmaps/Application/build.gradle index c5134fb4..292c2d14 100644 --- a/prebuilts/gradle/DisplayingBitmaps/Application/build.gradle +++ b/prebuilts/gradle/DisplayingBitmaps/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/DocumentCentricApps/Application/build.gradle b/prebuilts/gradle/DocumentCentricApps/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/DocumentCentricApps/Application/build.gradle +++ b/prebuilts/gradle/DocumentCentricApps/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/DocumentCentricRelinquishIdentity/Application/build.gradle b/prebuilts/gradle/DocumentCentricRelinquishIdentity/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/DocumentCentricRelinquishIdentity/Application/build.gradle +++ b/prebuilts/gradle/DocumentCentricRelinquishIdentity/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/DoneBar/Application/build.gradle b/prebuilts/gradle/DoneBar/Application/build.gradle index 0427861a..37884d80 100644 --- a/prebuilts/gradle/DoneBar/Application/build.gradle +++ b/prebuilts/gradle/DoneBar/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/DrawableTinting/Application/build.gradle b/prebuilts/gradle/DrawableTinting/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/DrawableTinting/Application/build.gradle +++ b/prebuilts/gradle/DrawableTinting/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/ElevationBasic/Application/build.gradle b/prebuilts/gradle/ElevationBasic/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/ElevationBasic/Application/build.gradle +++ b/prebuilts/gradle/ElevationBasic/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/ElevationDrag/Application/build.gradle b/prebuilts/gradle/ElevationDrag/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/ElevationDrag/Application/build.gradle +++ b/prebuilts/gradle/ElevationDrag/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/ElizaChat/Application/build.gradle b/prebuilts/gradle/ElizaChat/Application/build.gradle index f3cacbe1..3859b3ee 100644 --- a/prebuilts/gradle/ElizaChat/Application/build.gradle +++ b/prebuilts/gradle/ElizaChat/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/FloatingActionButtonBasic/Application/build.gradle b/prebuilts/gradle/FloatingActionButtonBasic/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/FloatingActionButtonBasic/Application/build.gradle +++ b/prebuilts/gradle/FloatingActionButtonBasic/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/FragmentTransition/Application/build.gradle b/prebuilts/gradle/FragmentTransition/Application/build.gradle index bfed04fa..c6b8c26a 100644 --- a/prebuilts/gradle/FragmentTransition/Application/build.gradle +++ b/prebuilts/gradle/FragmentTransition/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/HdrViewfinder/Application/build.gradle b/prebuilts/gradle/HdrViewfinder/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/HdrViewfinder/Application/build.gradle +++ b/prebuilts/gradle/HdrViewfinder/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/HorizontalPaging/Application/build.gradle b/prebuilts/gradle/HorizontalPaging/Application/build.gradle index 8380768f..8b72299a 100644 --- a/prebuilts/gradle/HorizontalPaging/Application/build.gradle +++ b/prebuilts/gradle/HorizontalPaging/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/ImmersiveMode/Application/build.gradle b/prebuilts/gradle/ImmersiveMode/Application/build.gradle index 05020be5..76169dee 100644 --- a/prebuilts/gradle/ImmersiveMode/Application/build.gradle +++ b/prebuilts/gradle/ImmersiveMode/Application/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" + compile "com.android.support:support-v4:21.0.2" } diff --git a/prebuilts/gradle/Interpolator/Application/build.gradle b/prebuilts/gradle/Interpolator/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/Interpolator/Application/build.gradle +++ b/prebuilts/gradle/Interpolator/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/JobScheduler/Application/build.gradle b/prebuilts/gradle/JobScheduler/Application/build.gradle index f3cacbe1..3859b3ee 100644 --- a/prebuilts/gradle/JobScheduler/Application/build.gradle +++ b/prebuilts/gradle/JobScheduler/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/JumpingJack/.google/packaging.yaml b/prebuilts/gradle/JumpingJack/.google/packaging.yaml index 618c275b..b2c99852 100644 --- a/prebuilts/gradle/JumpingJack/.google/packaging.yaml +++ b/prebuilts/gradle/JumpingJack/.google/packaging.yaml @@ -9,4 +9,9 @@ categories: [Wearable] languages: [Java] solutions: [Mobile] github: android-JumpingJack +level: INTERMEDIATE +icon: screenshots/web-icon.png +apiRefs: + - android:android.hardware.SensorEvent + - android:android.hardware.SensorEventManager license: apache2 diff --git a/prebuilts/gradle/JumpingJack/README.md b/prebuilts/gradle/JumpingJack/README.md index d87e86fb..f2c82c3e 100644 --- a/prebuilts/gradle/JumpingJack/README.md +++ b/prebuilts/gradle/JumpingJack/README.md @@ -1,7 +1,44 @@ Android JumpingJack Sample =================================== -Uses the Gravity sensor to count how many jumping jacks you have performed. +A basic sample showing how to use the Gravity sensor on the wearable device +by counting how many jumping jacks you have performed. + +Introduction +------------ + +[SensorEventListener][1] offers you methods used for receiving notifications from the +[SensorManager][2] when sensor values have changed. + +This example counts how many times Jumping Jakcs are performed by detecting the value +of the Gravity sensor by the following code: + +```java +@Override +public void onSensorChanged(SensorEvent event) { + detectJump(event.values[0], event.timestamp); +} + +private void detectJump(float xValue, long timestamp) { + if ((Math.abs(xValue) > GRAVITY_THRESHOLD)) { + if(timestamp - mLastTime < TIME_THRESHOLD_NS && mUp != (xValue > 0)) { + onJumpDetected(!mUp); + } + mUp = xValue > 0; + mLastTime = timestamp; + } +} +``` + +The detectJump method above assumes that when a person is wearing the watch, the x-component of gravity +as measured by the Gravity Sensor is +9.8 when the hand is downward and -9.8 when the hand +is upward (signs are reversed if the watch is worn on the right hand). Since the upward or +downward may not be completely accurate, we leave some room and instead of 9.8, we use +GRAVITY_THRESHOLD (7.0f). We also consider the up <-> down movement successful if it takes less than +TIME_THRESHOLD_NS (2000000000 nanoseconds). + +[1]: http://developer.android.com/reference/android/hardware/SensorEventListener.html +[2]: http://developer.android.com/reference/android/hardware/SensorManager.html Pre-requisites -------------- @@ -10,6 +47,11 @@ Pre-requisites - Android Build Tools v21.1.1 - Android Support Repository +Screenshots +------------- + +<img src="screenshots/jumping_jack.gif" height="400" alt="Screenshot"/> + Getting Started --------------- diff --git a/prebuilts/gradle/JumpingJack/screenshots/web-icon.png b/prebuilts/gradle/JumpingJack/screenshots/web-icon.png Binary files differnew file mode 100644 index 00000000..da3c00a9 --- /dev/null +++ b/prebuilts/gradle/JumpingJack/screenshots/web-icon.png diff --git a/prebuilts/gradle/LNotifications/Application/build.gradle b/prebuilts/gradle/LNotifications/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/LNotifications/Application/build.gradle +++ b/prebuilts/gradle/LNotifications/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/MediaBrowserService/.google/packaging.yaml b/prebuilts/gradle/MediaBrowserService/.google/packaging.yaml index a126b516..09141fd3 100644 --- a/prebuilts/gradle/MediaBrowserService/.google/packaging.yaml +++ b/prebuilts/gradle/MediaBrowserService/.google/packaging.yaml @@ -9,4 +9,12 @@ categories: [Media] languages: [Java] solutions: [Mobile] github: android-MediaBrowserService +level: ADVANCED +icon: screenshots/icon-web.png +apiRefs: + - android:android.service.media.MediaBrowserService + - android:android.media.browse.MediaBrowser + - android:android.media.session.MediaSession + - android:android.media.session.MediaController + - android:android.app.Notification.MediaStyle license: apache2 diff --git a/prebuilts/gradle/MediaBrowserService/Application/build.gradle b/prebuilts/gradle/MediaBrowserService/Application/build.gradle index 07e791da..bfccf049 100644 --- a/prebuilts/gradle/MediaBrowserService/Application/build.gradle +++ b/prebuilts/gradle/MediaBrowserService/Application/build.gradle @@ -13,9 +13,9 @@ apply plugin: 'com.android.application' dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MediaNotification.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MediaNotification.java index 4456fdac..68727239 100644 --- a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MediaNotification.java +++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MediaNotification.java @@ -37,7 +37,6 @@ import android.media.session.MediaSession; import android.media.session.PlaybackState; import android.os.AsyncTask; import android.util.LruCache; -import android.util.SparseArray; import com.example.android.mediabrowserservice.utils.BitmapHelper; import com.example.android.mediabrowserservice.utils.LogHelper; @@ -65,7 +64,6 @@ public class MediaNotification extends BroadcastReceiver { private MediaSession.Token mSessionToken; private MediaController mController; private MediaController.TransportControls mTransportControls; - private final SparseArray<PendingIntent> mIntents = new SparseArray<PendingIntent>(); private final LruCache<String, Bitmap> mAlbumArtCache; private PlaybackState mPlaybackState; @@ -75,6 +73,8 @@ public class MediaNotification extends BroadcastReceiver { private NotificationManager mNotificationManager; private Notification.Action mPlayPauseAction; + private PendingIntent mPauseIntent, mPlayIntent, mPreviousIntent, mNextIntent; + private String mCurrentAlbumArt; private int mNotificationColor; @@ -99,14 +99,14 @@ public class MediaNotification extends BroadcastReceiver { .getSystemService(Context.NOTIFICATION_SERVICE); String pkg = mService.getPackageName(); - mIntents.put(R.drawable.ic_pause_white_24dp, PendingIntent.getBroadcast(mService, 100, - new Intent(ACTION_PAUSE).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT)); - mIntents.put(R.drawable.ic_play_arrow_white_24dp, PendingIntent.getBroadcast(mService, 100, - new Intent(ACTION_PLAY).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT)); - mIntents.put(R.drawable.ic_skip_previous_white_24dp, PendingIntent.getBroadcast(mService, 100, - new Intent(ACTION_PREV).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT)); - mIntents.put(R.drawable.ic_skip_next_white_24dp, PendingIntent.getBroadcast(mService, 100, - new Intent(ACTION_NEXT).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT)); + mPauseIntent = PendingIntent.getBroadcast(mService, 100, + new Intent(ACTION_PAUSE).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); + mPlayIntent = PendingIntent.getBroadcast(mService, 100, + new Intent(ACTION_PLAY).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); + mPreviousIntent = PendingIntent.getBroadcast(mService, 100, + new Intent(ACTION_PREV).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); + mNextIntent = PendingIntent.getBroadcast(mService, 100, + new Intent(ACTION_NEXT).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); } protected int getNotificationColor() { @@ -241,8 +241,7 @@ public class MediaNotification extends BroadcastReceiver { if ((mPlaybackState.getActions() & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0) { mNotificationBuilder .addAction(R.drawable.ic_skip_previous_white_24dp, - mService.getString(R.string.label_previous), - mIntents.get(R.drawable.ic_skip_previous_white_24dp)); + mService.getString(R.string.label_previous), mPreviousIntent); playPauseActionIndex = 1; } @@ -251,8 +250,7 @@ public class MediaNotification extends BroadcastReceiver { // If skip to next action is enabled if ((mPlaybackState.getActions() & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) { mNotificationBuilder.addAction(R.drawable.ic_skip_next_white_24dp, - mService.getString(R.string.label_next), - mIntents.get(R.drawable.ic_skip_next_white_24dp)); + mService.getString(R.string.label_next), mNextIntent); } MediaDescription description = mMetadata.getDescription(); @@ -294,22 +292,24 @@ public class MediaNotification extends BroadcastReceiver { private void updatePlayPauseAction() { LogHelper.d(TAG, "updatePlayPauseAction"); - String playPauseLabel = ""; - int playPauseIcon; + String label; + int icon; + PendingIntent intent; if (mPlaybackState.getState() == PlaybackState.STATE_PLAYING) { - playPauseLabel = mService.getString(R.string.label_pause); - playPauseIcon = R.drawable.ic_pause_white_24dp; + label = mService.getString(R.string.label_pause); + icon = R.drawable.ic_pause_white_24dp; + intent = mPauseIntent; } else { - playPauseLabel = mService.getString(R.string.label_play); - playPauseIcon = R.drawable.ic_play_arrow_white_24dp; + label = mService.getString(R.string.label_play); + icon = R.drawable.ic_play_arrow_white_24dp; + intent = mPlayIntent; } if (mPlayPauseAction == null) { - mPlayPauseAction = new Notification.Action(playPauseIcon, playPauseLabel, - mIntents.get(playPauseIcon)); + mPlayPauseAction = new Notification.Action(icon, label, intent); } else { - mPlayPauseAction.icon = playPauseIcon; - mPlayPauseAction.title = playPauseLabel; - mPlayPauseAction.actionIntent = mIntents.get(playPauseIcon); + mPlayPauseAction.icon = icon; + mPlayPauseAction.title = label; + mPlayPauseAction.actionIntent = intent; } } diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_launcher.png Binary files differindex 47d6854e..05ef6f65 100644 --- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_launcher.png +++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_launcher.png Binary files differindex 01b53fd5..f894fb84 100644 --- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_launcher.png +++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differindex af762f2b..43ade5e6 100644 --- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_launcher.png +++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png Binary files differindex eef47aa3..3058c27f 100644 --- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png +++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxxhdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..6b4e4a21 --- /dev/null +++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxxhdpi/ic_launcher.png diff --git a/prebuilts/gradle/MediaBrowserService/README.md b/prebuilts/gradle/MediaBrowserService/README.md index 0072d93a..d3426511 100644 --- a/prebuilts/gradle/MediaBrowserService/README.md +++ b/prebuilts/gradle/MediaBrowserService/README.md @@ -12,6 +12,62 @@ connected to Android Auto, the same service provides data and callback to the Android Auto UI in the same manner as it provides them to the local UI. +Introduction +------------ + +To implement a MediaBrowserService, you need to: + +- Extend android.service.media.MediaBrowserService, implementing the media + browsing related methods onGetRoot and onLoadChildren; + +- In onCreate, start a new MediaSession and call super.setSessionToken() with + this MediaSession's token; + +- Set a MediaSession.Callback class on the MediaSession. The callback class + will receive all the user's actions, like play, pause, etc; + +- Handle all the actual music playing using any method your app prefers + (for example, the Android MediaPlayer class) + +- Whenever it changes, update info about the playing item and the playing + queue using MediaSession corresponding methods (setMetadata, + setPlaybackState, setQueue, setQueueTitle, etc) + +- Handle AudioManager focus change events and react appropriately + (e.g. pause when audio focus is lost) + + +To make it compatible with Android Auto, you also need to: + +- Declare a meta-data tag in AndroidManifest.xml linking to a xml resource + with a automotiveApp root element. For a media app, this must include + an <uses name="media"/> element as a child. + + For example, in AndroidManifest.xml: +``` + <meta-data android:name="com.google.android.gms.car.application" + android:resource="@xml/automotive_app_desc"/> +``` + + And in res/xml/automotive\_app\_desc.xml: +``` + <?xml version="1.0" encoding="utf-8"?> + <automotiveApp> + <uses name="media"/> + </automotiveApp> +``` + +- Declare and export the service in AndroidManifest.xml: +``` + <service + android:name=".service.MusicService" + android:exported="true"> + <intent-filter> + <action android:name="android.media.browse.MediaBrowserService" /> + </intent-filter> + </service> +``` + Pre-requisites -------------- @@ -19,6 +75,11 @@ Pre-requisites - Android Build Tools v21.1.1 - Android Support Repository +Screenshots +------------- + +<img src="screenshots/1-main.png" height="400" alt="Screenshot"/> <img src="screenshots/2-music-play.png" height="400" alt="Screenshot"/> <img src="screenshots/3-music-notification.png" height="400" alt="Screenshot"/> + Getting Started --------------- diff --git a/prebuilts/gradle/MediaBrowserService/screenshots/1-main.png b/prebuilts/gradle/MediaBrowserService/screenshots/1-main.png Binary files differnew file mode 100644 index 00000000..1b17d0e7 --- /dev/null +++ b/prebuilts/gradle/MediaBrowserService/screenshots/1-main.png diff --git a/prebuilts/gradle/MediaBrowserService/screenshots/2-music-play.png b/prebuilts/gradle/MediaBrowserService/screenshots/2-music-play.png Binary files differnew file mode 100644 index 00000000..1c1439cf --- /dev/null +++ b/prebuilts/gradle/MediaBrowserService/screenshots/2-music-play.png diff --git a/prebuilts/gradle/MediaBrowserService/screenshots/3-music-notification.png b/prebuilts/gradle/MediaBrowserService/screenshots/3-music-notification.png Binary files differnew file mode 100644 index 00000000..c86c045f --- /dev/null +++ b/prebuilts/gradle/MediaBrowserService/screenshots/3-music-notification.png diff --git a/prebuilts/gradle/MediaBrowserService/screenshots/icon-web.png b/prebuilts/gradle/MediaBrowserService/screenshots/icon-web.png Binary files differnew file mode 100644 index 00000000..99928a86 --- /dev/null +++ b/prebuilts/gradle/MediaBrowserService/screenshots/icon-web.png diff --git a/prebuilts/gradle/MediaEffects/Application/build.gradle b/prebuilts/gradle/MediaEffects/Application/build.gradle index 0427861a..37884d80 100644 --- a/prebuilts/gradle/MediaEffects/Application/build.gradle +++ b/prebuilts/gradle/MediaEffects/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/MediaRecorder/Application/build.gradle b/prebuilts/gradle/MediaRecorder/Application/build.gradle index 0427861a..37884d80 100644 --- a/prebuilts/gradle/MediaRecorder/Application/build.gradle +++ b/prebuilts/gradle/MediaRecorder/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/MediaRouter/Application/build.gradle b/prebuilts/gradle/MediaRouter/Application/build.gradle index f2fbc366..254d247b 100644 --- a/prebuilts/gradle/MediaRouter/Application/build.gradle +++ b/prebuilts/gradle/MediaRouter/Application/build.gradle @@ -17,12 +17,12 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" - compile "com.android.support:appcompat-v7:20.+" - compile "com.android.support:mediarouter-v7:20.+" + compile "com.android.support:appcompat-v7:21.0.2" + compile "com.android.support:mediarouter-v7:21.0.2" } // The sample build uses multiple directories to diff --git a/prebuilts/gradle/MessagingService/Application/build.gradle b/prebuilts/gradle/MessagingService/Application/build.gradle index 07e791da..bfccf049 100644 --- a/prebuilts/gradle/MessagingService/Application/build.gradle +++ b/prebuilts/gradle/MessagingService/Application/build.gradle @@ -13,9 +13,9 @@ apply plugin: 'com.android.application' dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-hdpi/ic_launcher.png b/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-hdpi/ic_launcher.png Binary files differindex 06d85f16..506cbc5a 100644 --- a/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-hdpi/ic_launcher.png +++ b/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-mdpi/ic_launcher.png b/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-mdpi/ic_launcher.png Binary files differindex 4e1cc86b..6296a036 100644 --- a/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-mdpi/ic_launcher.png +++ b/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differindex 92f1e2dd..52d3c5ec 100644 --- a/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-xhdpi/ic_launcher.png +++ b/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png Binary files differindex 2476cbdd..444fb390 100644 --- a/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png +++ b/prebuilts/gradle/MessagingService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/prebuilts/gradle/MessagingService/README.md b/prebuilts/gradle/MessagingService/README.md index bc7a3657..698adf40 100644 --- a/prebuilts/gradle/MessagingService/README.md +++ b/prebuilts/gradle/MessagingService/README.md @@ -9,16 +9,38 @@ Each unread conversation from a user is sent as a distinct notification. Introduction ------------ -This sample shows a simple service that sends [notifications][1] using -NotificationCompat. - -In addition to sending a notification, it also extends -the notification with a [CarExtender][2] to make it compatible with Android Auto. - -Each unread conversation from a user is sent as a distinct notification. - -[1]: https://developer.android.com/guide/topics/ui/notifiers/notifications.html -[2]: https://developer.android.com/reference/android/support/v4/app/NotificationCompat.CarExtender.html +#### Checklist while building a messaging app that supports Android Auto: +1. Ensure that Message notifications are extended using +NotificationCompat.Builder.extend(new CarExtender()...) +2. Declare a meta-data tag to your AndroidManifest.xml to specify that your app +is automotive enabled. + +example: AndroidManifest.xml + +``` + <meta-data android:name="com.google.android.gms.car.application" + android:resource="@xml/automotive_app_desc"/> +``` + +Include the following to indicate that the application wants to show notifications on +the Android Auto overview screen. + +example: res/xml/automotive\_app\_desc.xml +``` + <automotiveApp> + <uses name="notification"/> + </automotiveApp> +``` + +#### Flow +MessagingFragment is shown to the user. Depending on the button clicked, the MessagingService is +sent a message. MessagingService in turn creates notifications which can be viewed either on the +device or in the messaging-simulator. + +When a message is read, the associated PendingIntent is triggered and MessageReadReceiver is called +with the appropriate conversationId. Similarly, when a reply is received, the MessageReplyReceiver +is called with the appropriate conversationId. MessageLogger logs each event and shows them in a +TextView in MessagingFragment for correlation. Pre-requisites -------------- diff --git a/prebuilts/gradle/MessagingService/screenshots/icon-web.png b/prebuilts/gradle/MessagingService/screenshots/icon-web.png Binary files differindex 2476cbdd..3dfd2ec8 100644 --- a/prebuilts/gradle/MessagingService/screenshots/icon-web.png +++ b/prebuilts/gradle/MessagingService/screenshots/icon-web.png diff --git a/prebuilts/gradle/NavigationDrawer/Application/build.gradle b/prebuilts/gradle/NavigationDrawer/Application/build.gradle index c68979c3..bff2be09 100644 --- a/prebuilts/gradle/NavigationDrawer/Application/build.gradle +++ b/prebuilts/gradle/NavigationDrawer/Application/build.gradle @@ -18,10 +18,10 @@ repositories { dependencies { - compile "com.android.support:support-v13:20.+" - compile "com.android.support:appcompat-v7:20.+" - compile "com.android.support:recyclerview-v7:+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:appcompat-v7:21.0.2" + compile "com.android.support:recyclerview-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } // The sample build uses multiple directories to diff --git a/prebuilts/gradle/NetworkConnect/Application/build.gradle b/prebuilts/gradle/NetworkConnect/Application/build.gradle index 90737fcc..3e25a83b 100644 --- a/prebuilts/gradle/NetworkConnect/Application/build.gradle +++ b/prebuilts/gradle/NetworkConnect/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/PdfRendererBasic/Application/build.gradle b/prebuilts/gradle/PdfRendererBasic/Application/build.gradle index e77578c4..e86efa99 100644 --- a/prebuilts/gradle/PdfRendererBasic/Application/build.gradle +++ b/prebuilts/gradle/PdfRendererBasic/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/PermissionRequest/.google/packaging.yaml b/prebuilts/gradle/PermissionRequest/.google/packaging.yaml new file mode 100644 index 00000000..fc79469a --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/.google/packaging.yaml @@ -0,0 +1,18 @@ +# GOOGLE SAMPLE PACKAGING DATA +# +# This file is used by Google as part of our samples packaging process. +# End users may safely ignore this file. It has no relevance to other systems. +--- +status: PUBLISHED +technologies: [Android] +categories: [Content] +languages: [Java] +solutions: [Mobile] +github: android-PermissionRequest +level: INTERMEDIATE +icon: screenshots/icon_web.png +apiRefs: + - android:android.webkit.PermissionRequest + - android:android.webkit.WebView + - android:android.webkit.WebChromeClient +license: apache2 diff --git a/prebuilts/gradle/PermissionRequest/Application/build.gradle b/prebuilts/gradle/PermissionRequest/Application/build.gradle new file mode 100644 index 00000000..71ddf508 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/build.gradle @@ -0,0 +1,70 @@ +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:1.0.0' + } +} + +apply plugin: 'com.android.application' + +repositories { + jcenter() +} + + +dependencies { + + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" + +} + +// The sample build uses multiple directories to +// keep boilerplate and common code separate from +// the main sample code. +List<String> dirs = [ + 'main', // main sample code; look here for the interesting stuff. + 'common', // components that are reused by multiple samples + 'template'] // boilerplate code that is generated by the sample template process + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 21 + targetSdkVersion 21 + } + + sourceSets { + main { + dirs.each { dir -> + java.srcDirs "src/${dir}/java" + res.srcDirs "src/${dir}/res" + } + } + androidTest.setRoot('tests') + androidTest.java.srcDirs = ['tests/src'] + + } + +} + + + + + + + + + + + + + + + diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/AndroidManifest.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/AndroidManifest.xml new file mode 100644 index 00000000..f8fd050c --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/AndroidManifest.xml @@ -0,0 +1,39 @@ +<?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.permissionrequest" + android:versionCode="1" + android:versionName="1.0"> + + <uses-permission android:name="android.permission.INTERNET"/> + <uses-permission android:name="android.permission.CAMERA"/> + + <application android:allowBackup="true" + android:label="@string/app_name" + android:icon="@drawable/ic_launcher" + android:theme="@style/AppTheme"> + + <activity android:name=".MainActivity" + 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/prebuilts/gradle/PermissionRequest/Application/src/main/assets/sample.css b/prebuilts/gradle/PermissionRequest/Application/src/main/assets/sample.css new file mode 100644 index 00000000..9d1364ce --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/assets/sample.css @@ -0,0 +1,36 @@ +/* + * 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. + */ + +body { + text-align: center; +} + +div { + margin-bottom: 8px; +} + +button { + height: 48px; + width: 80px; + font-weight: bold; + font-size: 14pt; +} + +video { + width: 240px; + height: 180px; + transform: scaleX(-1); /* Mirror */ +} diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/assets/sample.html b/prebuilts/gradle/PermissionRequest/Application/src/main/assets/sample.html new file mode 100644 index 00000000..a9729a33 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/assets/sample.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<!-- + 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. +--> +<html> +<head> + <title>sample</title> + <link rel="stylesheet" href="sample.css"> +</head> +<body> + +<div> + <button id="toggle">Start</button> +</div> +<video id="video" autoplay></video> + +<script src="sample.js"></script> +</body> +</html> diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/assets/sample.js b/prebuilts/gradle/PermissionRequest/Application/src/main/assets/sample.js new file mode 100644 index 00000000..e2806a0d --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/assets/sample.js @@ -0,0 +1,56 @@ +/* + * 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. + */ + +(function () { + "use strict"; + + navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia; + window.URL = window.URL || window.webkitURL; + + window.onload = function () { + + var video = document.querySelector('#video'), + toggle = document.querySelector('#toggle'), + stream = null; + + if (!navigator.getUserMedia) { + console.error('getUserMedia not supported'); + } + + toggle.addEventListener('click', function () { + if (null === stream) { + // This call to "getUserMedia" initiates a PermissionRequest in the WebView. + navigator.getUserMedia({ video: true }, function (s) { + stream = s; + video.src = window.URL.createObjectURL(stream); + toggle.innerText = 'Stop'; + console.log('Started'); + }, function (error) { + console.error('Error starting camera. Denied.'); + }); + } else { + stream.stop(); + stream = null; + toggle.innerText = 'Start'; + console.log('Stopped'); + } + }); + + console.log('Page loaded'); + + }; + +})(); diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/activities/SampleActivityBase.java b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/activities/SampleActivityBase.java new file mode 100644 index 00000000..3228927b --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/activities/SampleActivityBase.java @@ -0,0 +1,52 @@ +/* +* 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. +*/ + +package com.example.android.common.activities; + +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; + +import com.example.android.common.logger.Log; +import com.example.android.common.logger.LogWrapper; + +/** + * Base launcher activity, to handle most of the common plumbing for samples. + */ +public class SampleActivityBase extends FragmentActivity { + + public static final String TAG = "SampleActivityBase"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + protected void onStart() { + super.onStart(); + initializeLogging(); + } + + /** Set up targets to receive log data */ + public void initializeLogging() { + // Using Log, front-end to the logging chain, emulates android.util.log method signatures. + // Wraps Android's native log framework + LogWrapper logWrapper = new LogWrapper(); + Log.setLogNode(logWrapper); + + Log.i(TAG, "Ready"); + } +} diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/Log.java b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/Log.java new file mode 100644 index 00000000..17503c56 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/Log.java @@ -0,0 +1,236 @@ +/* + * Copyright (C) 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. + */ +package com.example.android.common.logger; + +/** + * Helper class for a list (or tree) of LoggerNodes. + * + * <p>When this is set as the head of the list, + * an instance of it can function as a drop-in replacement for {@link android.util.Log}. + * Most of the methods in this class server only to map a method call in Log to its equivalent + * in LogNode.</p> + */ +public class Log { + // Grabbing the native values from Android's native logging facilities, + // to make for easy migration and interop. + public static final int NONE = -1; + public static final int VERBOSE = android.util.Log.VERBOSE; + public static final int DEBUG = android.util.Log.DEBUG; + public static final int INFO = android.util.Log.INFO; + public static final int WARN = android.util.Log.WARN; + public static final int ERROR = android.util.Log.ERROR; + public static final int ASSERT = android.util.Log.ASSERT; + + // Stores the beginning of the LogNode topology. + private static LogNode mLogNode; + + /** + * Returns the next LogNode in the linked list. + */ + public static LogNode getLogNode() { + return mLogNode; + } + + /** + * Sets the LogNode data will be sent to. + */ + public static void setLogNode(LogNode node) { + mLogNode = node; + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void println(int priority, String tag, String msg, Throwable tr) { + if (mLogNode != null) { + mLogNode.println(priority, tag, msg, tr); + } + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + */ + public static void println(int priority, String tag, String msg) { + println(priority, tag, msg, null); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void v(String tag, String msg, Throwable tr) { + println(VERBOSE, tag, msg, tr); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void v(String tag, String msg) { + v(tag, msg, null); + } + + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void d(String tag, String msg, Throwable tr) { + println(DEBUG, tag, msg, tr); + } + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void d(String tag, String msg) { + d(tag, msg, null); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void i(String tag, String msg, Throwable tr) { + println(INFO, tag, msg, tr); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void i(String tag, String msg) { + i(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, String msg, Throwable tr) { + println(WARN, tag, msg, tr); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void w(String tag, String msg) { + w(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, Throwable tr) { + w(tag, null, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void e(String tag, String msg, Throwable tr) { + println(ERROR, tag, msg, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void e(String tag, String msg) { + e(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, String msg, Throwable tr) { + println(ASSERT, tag, msg, tr); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void wtf(String tag, String msg) { + wtf(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, Throwable tr) { + wtf(tag, null, tr); + } +} diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/LogFragment.java b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/LogFragment.java new file mode 100644 index 00000000..b302acd4 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/LogFragment.java @@ -0,0 +1,109 @@ +/* +* 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. +*/ +/* + * 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. + */ + +package com.example.android.common.logger; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ScrollView; + +/** + * Simple fraggment which contains a LogView and uses is to output log data it receives + * through the LogNode interface. + */ +public class LogFragment extends Fragment { + + private LogView mLogView; + private ScrollView mScrollView; + + public LogFragment() {} + + public View inflateViews() { + mScrollView = new ScrollView(getActivity()); + ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mScrollView.setLayoutParams(scrollParams); + + mLogView = new LogView(getActivity()); + ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams); + logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + mLogView.setLayoutParams(logParams); + mLogView.setClickable(true); + mLogView.setFocusable(true); + mLogView.setTypeface(Typeface.MONOSPACE); + + // Want to set padding as 16 dips, setPadding takes pixels. Hooray math! + int paddingDips = 16; + double scale = getResources().getDisplayMetrics().density; + int paddingPixels = (int) ((paddingDips * (scale)) + .5); + mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels); + mLogView.setCompoundDrawablePadding(paddingPixels); + + mLogView.setGravity(Gravity.BOTTOM); + mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium); + + mScrollView.addView(mLogView); + return mScrollView; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View result = inflateViews(); + + mLogView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + mScrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + }); + return result; + } + + public LogView getLogView() { + return mLogView; + } +}
\ No newline at end of file diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/LogNode.java b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/LogNode.java new file mode 100644 index 00000000..bc37cabc --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/LogNode.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 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.common.logger; + +/** + * Basic interface for a logging system that can output to one or more targets. + * Note that in addition to classes that will output these logs in some format, + * one can also implement this interface over a filter and insert that in the chain, + * such that no targets further down see certain data, or see manipulated forms of the data. + * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data + * it received to HTML and sent it along to the next node in the chain, without printing it + * anywhere. + */ +public interface LogNode { + + /** + * Instructs first LogNode in the list to print the log data provided. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public void println(int priority, String tag, String msg, Throwable tr); + +} diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/LogView.java b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/LogView.java new file mode 100644 index 00000000..c01542b9 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/LogView.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 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. + */ +package com.example.android.common.logger; + +import android.app.Activity; +import android.content.Context; +import android.util.*; +import android.widget.TextView; + +/** Simple TextView which is used to output log data received through the LogNode interface. +*/ +public class LogView extends TextView implements LogNode { + + public LogView(Context context) { + super(context); + } + + public LogView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LogView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Formats the log data and prints it out to the LogView. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + + + String priorityStr = null; + + // For the purposes of this View, we want to print the priority as readable text. + switch(priority) { + case android.util.Log.VERBOSE: + priorityStr = "VERBOSE"; + break; + case android.util.Log.DEBUG: + priorityStr = "DEBUG"; + break; + case android.util.Log.INFO: + priorityStr = "INFO"; + break; + case android.util.Log.WARN: + priorityStr = "WARN"; + break; + case android.util.Log.ERROR: + priorityStr = "ERROR"; + break; + case android.util.Log.ASSERT: + priorityStr = "ASSERT"; + break; + default: + break; + } + + // Handily, the Log class has a facility for converting a stack trace into a usable string. + String exceptionStr = null; + if (tr != null) { + exceptionStr = android.util.Log.getStackTraceString(tr); + } + + // Take the priority, tag, message, and exception, and concatenate as necessary + // into one usable line of text. + final StringBuilder outputBuilder = new StringBuilder(); + + String delimiter = "\t"; + appendIfNotNull(outputBuilder, priorityStr, delimiter); + appendIfNotNull(outputBuilder, tag, delimiter); + appendIfNotNull(outputBuilder, msg, delimiter); + appendIfNotNull(outputBuilder, exceptionStr, delimiter); + + // In case this was originally called from an AsyncTask or some other off-UI thread, + // make sure the update occurs within the UI thread. + ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() { + @Override + public void run() { + // Display the text we just generated within the LogView. + appendToLog(outputBuilder.toString()); + } + }))); + + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } + + public LogNode getNext() { + return mNext; + } + + public void setNext(LogNode node) { + mNext = node; + } + + /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since + * the logger takes so many arguments that might be null, this method helps cut out some of the + * agonizing tedium of writing the same 3 lines over and over. + * @param source StringBuilder containing the text to append to. + * @param addStr The String to append + * @param delimiter The String to separate the source and appended strings. A tab or comma, + * for instance. + * @return The fully concatenated String as a StringBuilder + */ + private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) { + if (addStr != null) { + if (addStr.length() == 0) { + delimiter = ""; + } + + return source.append(addStr).append(delimiter); + } + return source; + } + + // The next LogNode in the chain. + LogNode mNext; + + /** Outputs the string as a new line of log data in the LogView. */ + public void appendToLog(String s) { + append("\n" + s); + } + + +} diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/LogWrapper.java b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/LogWrapper.java new file mode 100644 index 00000000..16a9e7ba --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/LogWrapper.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 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.common.logger; + +import android.util.Log; + +/** + * Helper class which wraps Android's native Log utility in the Logger interface. This way + * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously. + */ +public class LogWrapper implements LogNode { + + // For piping: The next node to receive Log data after this one has done its work. + private LogNode mNext; + + /** + * Returns the next LogNode in the linked list. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + + /** + * Prints data out to the console using Android's native log mechanism. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + // There actually are log methods that don't take a msg parameter. For now, + // if that's the case, just convert null to the empty string and move on. + String useMsg = msg; + if (useMsg == null) { + useMsg = ""; + } + + // If an exeption was provided, convert that exception to a usable string and attach + // it to the end of the msg method. + if (tr != null) { + msg += "\n" + Log.getStackTraceString(tr); + } + + // This is functionally identical to Log.x(tag, useMsg); + // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg) + Log.println(priority, tag, useMsg); + + // If this isn't the last node in the chain, move things along. + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } +} diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.java b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.java new file mode 100644 index 00000000..19967dcd --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 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. + */ +package com.example.android.common.logger; + +/** + * Simple {@link LogNode} filter, removes everything except the message. + * Useful for situations like on-screen log output where you don't want a lot of metadata displayed, + * just easy-to-read message updates as they're happening. + */ +public class MessageOnlyLogFilter implements LogNode { + + LogNode mNext; + + /** + * Takes the "next" LogNode as a parameter, to simplify chaining. + * + * @param next The next LogNode in the pipeline. + */ + public MessageOnlyLogFilter(LogNode next) { + mNext = next; + } + + public MessageOnlyLogFilter() { + } + + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + if (mNext != null) { + getNext().println(Log.NONE, null, msg, null); + } + } + + /** + * Returns the next LogNode in the chain. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + +} diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/permissionrequest/ConfirmationDialogFragment.java b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/permissionrequest/ConfirmationDialogFragment.java new file mode 100644 index 00000000..7dae56ef --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/permissionrequest/ConfirmationDialogFragment.java @@ -0,0 +1,79 @@ +/* + * 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.permissionrequest; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.text.TextUtils; + +/** + * Prompts the user to confirm permission request. + */ +public class ConfirmationDialogFragment extends DialogFragment { + + private static final String ARG_RESOURCES = "resources"; + + /** + * Creates a new instance of ConfirmationDialogFragment. + * + * @param resources The list of resources requested by PermissionRequeste. + * @return A new instance. + */ + public static ConfirmationDialogFragment newInstance(String[] resources) { + ConfirmationDialogFragment fragment = new ConfirmationDialogFragment(); + Bundle args = new Bundle(); + args.putStringArray(ARG_RESOURCES, resources); + fragment.setArguments(args); + return fragment; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + String[] resources = getArguments().getStringArray(ARG_RESOURCES); + return new AlertDialog.Builder(getActivity()) + .setMessage(getString(R.string.confirmation, TextUtils.join("\n", resources))) + .setNegativeButton(R.string.deny, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + ((Listener) getParentFragment()).onConfirmation(false); + } + }) + .setPositiveButton(R.string.allow, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + ((Listener) getParentFragment()).onConfirmation(true); + } + }) + .create(); + } + + /** + * Callback for the user's response. + */ + public interface Listener { + + /** + * Called when the PermissoinRequest is allowed or denied by the user. + * + * @param allowed True if the user allowed the request. + */ + public void onConfirmation(boolean allowed); + } + +} diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/permissionrequest/MainActivity.java b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/permissionrequest/MainActivity.java new file mode 100644 index 00000000..a11849fc --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/permissionrequest/MainActivity.java @@ -0,0 +1,109 @@ +/* +* 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. +*/ + +package com.example.android.permissionrequest; + +import android.os.Bundle; +import android.support.v4.app.FragmentTransaction; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.ViewAnimator; + +import com.example.android.common.activities.SampleActivityBase; +import com.example.android.common.logger.Log; +import com.example.android.common.logger.LogFragment; +import com.example.android.common.logger.LogWrapper; +import com.example.android.common.logger.MessageOnlyLogFilter; + +/** + * A simple launcher activity containing a summary sample description, sample log and a custom + * {@link android.support.v4.app.Fragment} which can display a view. + * <p> + * For devices with displays with a width of 720dp or greater, the sample log is always visible, + * on other devices it's visibility is controlled by an item on the Action Bar. + */ +public class MainActivity extends SampleActivityBase { + + public static final String TAG = "MainActivity"; + + // Whether the Log Fragment is currently shown + private boolean mLogShown; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + if (savedInstanceState == null) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + PermissionRequestFragment fragment = new PermissionRequestFragment(); + transaction.replace(R.id.sample_content_fragment, fragment); + transaction.commit(); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.main, menu); + return true; + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + MenuItem logToggle = menu.findItem(R.id.menu_toggle_log); + logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator); + logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log); + + return super.onPrepareOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch(item.getItemId()) { + case R.id.menu_toggle_log: + mLogShown = !mLogShown; + ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output); + if (mLogShown) { + output.setDisplayedChild(1); + } else { + output.setDisplayedChild(0); + } + supportInvalidateOptionsMenu(); + return true; + } + return super.onOptionsItemSelected(item); + } + + /** Create a chain of targets that will receive log data */ + @Override + public void initializeLogging() { + // Wraps Android's native log framework. + LogWrapper logWrapper = new LogWrapper(); + // Using Log, front-end to the logging chain, emulates android.util.log method signatures. + Log.setLogNode(logWrapper); + + // Filter strips out everything except the message text. + MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter(); + logWrapper.setNext(msgFilter); + + // On screen logging via a fragment with a TextView. + LogFragment logFragment = (LogFragment) getSupportFragmentManager() + .findFragmentById(R.id.log_fragment); + msgFilter.setNext(logFragment.getLogView()); + + Log.i(TAG, "Ready"); + } +} diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/permissionrequest/PermissionRequestFragment.java b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/permissionrequest/PermissionRequestFragment.java new file mode 100644 index 00000000..44f1d6ec --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/permissionrequest/PermissionRequestFragment.java @@ -0,0 +1,180 @@ +/* + * 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.permissionrequest; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.ConsoleMessage; +import android.webkit.PermissionRequest; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; + +import com.example.android.common.logger.Log; + +/** + * This fragment shows a {@link WebView} and loads a web app from the {@link SimpleWebServer}. + */ +public class PermissionRequestFragment extends Fragment + implements ConfirmationDialogFragment.Listener { + + private static final String TAG = PermissionRequestFragment.class.getSimpleName(); + + private static final String FRAGMENT_DIALOG = "dialog"; + + /** + * We use this web server to serve HTML files in the assets folder. This is because we cannot + * use the JavaScript method "getUserMedia" from "file:///android_assets/..." URLs. + */ + private SimpleWebServer mWebServer; + + /** + * A reference to the {@link WebView}. + */ + private WebView mWebView; + + /** + * This field stores the {@link PermissionRequest} from the web application until it is allowed + * or denied by user. + */ + private PermissionRequest mPermissionRequest; + + /** + * For testing. + */ + private ConsoleMonitor mConsoleMonitor; + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_permission_request, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + mWebView = (WebView) view.findViewById(R.id.web_view); + // Here, we use #mWebChromeClient with implementation for handling PermissionRequests. + mWebView.setWebChromeClient(mWebChromeClient); + configureWebSettings(mWebView.getSettings()); + } + + @Override + public void onResume() { + super.onResume(); + final int port = 8080; + mWebServer = new SimpleWebServer(port, getResources().getAssets()); + mWebServer.start(); + mWebView.loadUrl("http://localhost:" + port + "/sample.html"); + } + + @Override + public void onPause() { + mWebServer.stop(); + super.onPause(); + } + + @SuppressLint("SetJavaScriptEnabled") + private static void configureWebSettings(WebSettings settings) { + settings.setJavaScriptEnabled(true); + } + + /** + * This {@link WebChromeClient} has implementation for handling {@link PermissionRequest}. + */ + private WebChromeClient mWebChromeClient = new WebChromeClient() { + + // This method is called when the web content is requesting permission to access some + // resources. + @Override + public void onPermissionRequest(PermissionRequest request) { + Log.i(TAG, "onPermissionRequest"); + mPermissionRequest = request; + ConfirmationDialogFragment.newInstance(request.getResources()) + .show(getChildFragmentManager(), FRAGMENT_DIALOG); + } + + // This method is called when the permission request is canceled by the web content. + @Override + public void onPermissionRequestCanceled(PermissionRequest request) { + Log.i(TAG, "onPermissionRequestCanceled"); + // We dismiss the prompt UI here as the request is no longer valid. + mPermissionRequest = null; + DialogFragment fragment = (DialogFragment) getChildFragmentManager() + .findFragmentByTag(FRAGMENT_DIALOG); + if (null != fragment) { + fragment.dismiss(); + } + } + + @Override + public boolean onConsoleMessage(@NonNull ConsoleMessage message) { + switch (message.messageLevel()) { + case TIP: + Log.v(TAG, message.message()); + break; + case LOG: + Log.i(TAG, message.message()); + break; + case WARNING: + Log.w(TAG, message.message()); + break; + case ERROR: + Log.e(TAG, message.message()); + break; + case DEBUG: + Log.d(TAG, message.message()); + break; + } + if (null != mConsoleMonitor) { + mConsoleMonitor.onConsoleMessage(message); + } + return true; + } + + }; + + @Override + public void onConfirmation(boolean allowed) { + if (allowed) { + mPermissionRequest.grant(mPermissionRequest.getResources()); + Log.d(TAG, "Permission granted."); + } else { + mPermissionRequest.deny(); + Log.d(TAG, "Permission request denied."); + } + mPermissionRequest = null; + } + + public void setConsoleMonitor(ConsoleMonitor monitor) { + mConsoleMonitor = monitor; + } + + /** + * For testing. + */ + public interface ConsoleMonitor { + public void onConsoleMessage(ConsoleMessage message); + } + +} diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/permissionrequest/SimpleWebServer.java b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/permissionrequest/SimpleWebServer.java new file mode 100644 index 00000000..36b7c469 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/java/com/example/android/permissionrequest/SimpleWebServer.java @@ -0,0 +1,222 @@ +/* + * 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.permissionrequest; + +import android.content.res.AssetManager; +import android.text.TextUtils; +import android.util.Log; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; + +/** + * Implementation of a very basic HTTP server. The contents are loaded from the assets folder. This + * server handles one request at a time. It only supports GET method. + */ +public class SimpleWebServer implements Runnable { + + private static final String TAG = "SimpleWebServer"; + + /** + * The port number we listen to + */ + private final int mPort; + + /** + * {@link android.content.res.AssetManager} for loading files to serve. + */ + private final AssetManager mAssets; + + /** + * True if the server is running. + */ + private boolean mIsRunning; + + /** + * The {@link java.net.ServerSocket} that we listen to. + */ + private ServerSocket mServerSocket; + + /** + * WebServer constructor. + */ + public SimpleWebServer(int port, AssetManager assets) { + mPort = port; + mAssets = assets; + } + + /** + * This method starts the web server listening to the specified port. + */ + public void start() { + mIsRunning = true; + new Thread(this).start(); + } + + /** + * This method stops the web server + */ + public void stop() { + try { + mIsRunning = false; + if (null != mServerSocket) { + mServerSocket.close(); + mServerSocket = null; + } + } catch (IOException e) { + Log.e(TAG, "Error closing the server socket.", e); + } + } + + @Override + public void run() { + try { + mServerSocket = new ServerSocket(mPort); + while (mIsRunning) { + Socket socket = mServerSocket.accept(); + handle(socket); + socket.close(); + } + } catch (SocketException e) { + // The server was stopped; ignore. + } catch (IOException e) { + Log.e(TAG, "Web server error.", e); + } + } + + /** + * Respond to a request from a client. + * + * @param socket The client socket. + * @throws IOException + */ + private void handle(Socket socket) throws IOException { + BufferedReader reader = null; + PrintStream output = null; + try { + String route = null; + + // Read HTTP headers and parse out the route. + reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); + String line; + while (!TextUtils.isEmpty(line = reader.readLine())) { + if (line.startsWith("GET /")) { + int start = line.indexOf('/') + 1; + int end = line.indexOf(' ', start); + route = line.substring(start, end); + break; + } + } + + // Output stream that we send the response to + output = new PrintStream(socket.getOutputStream()); + + // Prepare the content to send. + if (null == route) { + writeServerError(output); + return; + } + byte[] bytes = loadContent(route); + if (null == bytes) { + writeServerError(output); + return; + } + + // Send out the content. + output.println("HTTP/1.0 200 OK"); + output.println("Content-Type: " + detectMimeType(route)); + output.println("Content-Length: " + bytes.length); + output.println(); + output.write(bytes); + output.flush(); + } finally { + if (null != output) { + output.close(); + } + if (null != reader) { + reader.close(); + } + } + } + + /** + * Writes a server error response (HTTP/1.0 500) to the given output stream. + * + * @param output The output stream. + */ + private void writeServerError(PrintStream output) { + output.println("HTTP/1.0 500 Internal Server Error"); + output.flush(); + } + + /** + * Loads all the content of {@code fileName}. + * + * @param fileName The name of the file. + * @return The content of the file. + * @throws IOException + */ + private byte[] loadContent(String fileName) throws IOException { + InputStream input = null; + try { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + input = mAssets.open(fileName); + byte[] buffer = new byte[1024]; + int size; + while (-1 != (size = input.read(buffer))) { + output.write(buffer, 0, size); + } + output.flush(); + return output.toByteArray(); + } catch (FileNotFoundException e) { + return null; + } finally { + if (null != input) { + input.close(); + } + } + } + + /** + * Detects the MIME type from the {@code fileName}. + * + * @param fileName The name of the file. + * @return A MIME type. + */ + private String detectMimeType(String fileName) { + if (TextUtils.isEmpty(fileName)) { + return null; + } else if (fileName.endsWith(".html")) { + return "text/html"; + } else if (fileName.endsWith(".js")) { + return "application/javascript"; + } else if (fileName.endsWith(".css")) { + return "text/css"; + } else { + return "application/octet-stream"; + } + } + +} diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-hdpi/ic_launcher.png b/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..4dae25b0 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-hdpi/tile.9.png b/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-hdpi/tile.9.png Binary files differnew file mode 100644 index 00000000..13586288 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-hdpi/tile.9.png diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-mdpi/ic_launcher.png b/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..e896d49b --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..5309f55e --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..61b137b8 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/layout-w720dp/activity_main.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/res/layout-w720dp/activity_main.xml new file mode 100755 index 00000000..c9a52f62 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/layout-w720dp/activity_main.xml @@ -0,0 +1,73 @@ +<!-- + 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. + --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:id="@+id/sample_main_layout"> + + <LinearLayout + android:id="@+id/sample_output" + android:layout_width="0px" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="vertical"> + + <FrameLayout + style="@style/Widget.SampleMessageTile" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + style="@style/Widget.SampleMessage" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingLeft="@dimen/margin_medium" + android:paddingRight="@dimen/margin_medium" + android:paddingTop="@dimen/margin_large" + android:paddingBottom="@dimen/margin_large" + android:text="@string/intro_message" /> + </FrameLayout> + + <View + android:layout_width="match_parent" + android:layout_height="1dp" + android:background="@android:color/darker_gray" /> + + <fragment + android:name="com.example.android.common.logger.LogFragment" + android:id="@+id/log_fragment" + android:layout_width="match_parent" + android:layout_height="0px" + android:layout_weight="1" /> + + </LinearLayout> + + <View + android:layout_width="1dp" + android:layout_height="match_parent" + android:background="@android:color/darker_gray" /> + + <FrameLayout + android:id="@+id/sample_content_fragment" + android:layout_weight="2" + android:layout_width="0px" + android:layout_height="match_parent" /> + +</LinearLayout> + + diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/layout/activity_main.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/res/layout/activity_main.xml new file mode 100755 index 00000000..1ae4f981 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/layout/activity_main.xml @@ -0,0 +1,65 @@ +<!-- + 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. + --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:id="@+id/sample_main_layout"> + + <ViewAnimator + android:id="@+id/sample_output" + android:layout_width="match_parent" + android:layout_height="0px" + android:layout_weight="1"> + + <ScrollView + style="@style/Widget.SampleMessageTile" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <TextView + style="@style/Widget.SampleMessage" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingLeft="@dimen/horizontal_page_margin" + android:paddingRight="@dimen/horizontal_page_margin" + android:paddingTop="@dimen/vertical_page_margin" + android:paddingBottom="@dimen/vertical_page_margin" + android:text="@string/intro_message" /> + </ScrollView> + + <fragment + android:name="com.example.android.common.logger.LogFragment" + android:id="@+id/log_fragment" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + </ViewAnimator> + + <View + android:layout_width="match_parent" + android:layout_height="1dp" + android:background="@android:color/darker_gray" /> + + <FrameLayout + android:id="@+id/sample_content_fragment" + android:layout_weight="2" + android:layout_width="match_parent" + android:layout_height="0px" /> + +</LinearLayout> + diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/layout/fragment_permission_request.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/res/layout/fragment_permission_request.xml new file mode 100644 index 00000000..2e97a0ae --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/layout/fragment_permission_request.xml @@ -0,0 +1,27 @@ +<?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:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <WebView + android:id="@+id/web_view" + android:layout_width="match_parent" + android:layout_height="match_parent"/> + +</LinearLayout> diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/menu/main.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/res/menu/main.xml new file mode 100644 index 00000000..b49c2c52 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/menu/main.xml @@ -0,0 +1,21 @@ +<!-- + 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. + --> + +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/menu_toggle_log" + android:showAsAction="always" + android:title="@string/sample_show_log" /> +</menu> diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-sw600dp/template-dimens.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-sw600dp/template-dimens.xml new file mode 100644 index 00000000..22074a2b --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-sw600dp/template-dimens.xml @@ -0,0 +1,24 @@ +<!-- + 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. + --> + +<resources> + + <!-- Semantic definitions --> + + <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen> + <dimen name="vertical_page_margin">@dimen/margin_medium</dimen> + +</resources> diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-sw600dp/template-styles.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-sw600dp/template-styles.xml new file mode 100644 index 00000000..03d19741 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-sw600dp/template-styles.xml @@ -0,0 +1,25 @@ +<!-- + 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. + --> + +<resources> + + <style name="Widget.SampleMessage"> + <item name="android:textAppearance">?android:textAppearanceLarge</item> + <item name="android:lineSpacingMultiplier">1.2</item> + <item name="android:shadowDy">-6.5</item> + </style> + +</resources> diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-v11/template-styles.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-v11/template-styles.xml new file mode 100644 index 00000000..8c1ea66f --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-v11/template-styles.xml @@ -0,0 +1,22 @@ +<!-- + 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. + --> + +<resources> + + <!-- Activity themes --> + <style name="Theme.Base" parent="android:Theme.Holo.Light" /> + +</resources> diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-v21/base-colors.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-v21/base-colors.xml new file mode 100644 index 00000000..34c9cd13 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-v21/base-colors.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<resources> + + +</resources> diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-v21/base-template-styles.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-v21/base-template-styles.xml new file mode 100644 index 00000000..0b2948f7 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values-v21/base-template-styles.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<resources> + + <!-- Activity themes --> + <style name="Theme.Base" parent="android:Theme.Material.Light"> + </style> + +</resources> diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/base-strings.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/base-strings.xml new file mode 100644 index 00000000..c66a246a --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/base-strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<resources> + <string name="app_name">PermissionRequest</string> + <string name="intro_message"> + <![CDATA[ + + + This sample shows how to handle PermissionRequest coming from web apps inside of a + WebView. + + + ]]> + </string> +</resources> diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/fragmentview_strings.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/fragmentview_strings.xml new file mode 100755 index 00000000..7b9d9ec4 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/fragmentview_strings.xml @@ -0,0 +1,19 @@ +<!-- + 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. +--> +<resources> + <string name="sample_show_log">Show Log</string> + <string name="sample_hide_log">Hide Log</string> +</resources> diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/strings.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/strings.xml new file mode 100644 index 00000000..c3e5574d --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/strings.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> + <string name="confirmation">This web page wants to use following resources:\n\n%s</string> + <string name="allow">Allow</string> + <string name="deny">Deny</string> +</resources> diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/template-dimens.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/template-dimens.xml new file mode 100644 index 00000000..39e710b5 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/template-dimens.xml @@ -0,0 +1,32 @@ +<!-- + 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. + --> + +<resources> + + <!-- Define standard dimensions to comply with Holo-style grids and rhythm. --> + + <dimen name="margin_tiny">4dp</dimen> + <dimen name="margin_small">8dp</dimen> + <dimen name="margin_medium">16dp</dimen> + <dimen name="margin_large">32dp</dimen> + <dimen name="margin_huge">64dp</dimen> + + <!-- Semantic definitions --> + + <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen> + <dimen name="vertical_page_margin">@dimen/margin_medium</dimen> + +</resources> diff --git a/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/template-styles.xml b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/template-styles.xml new file mode 100644 index 00000000..6e7d593d --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/src/main/res/values/template-styles.xml @@ -0,0 +1,42 @@ +<!-- + 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. + --> + +<resources> + + <!-- Activity themes --> + + <style name="Theme.Base" parent="android:Theme.Light" /> + + <style name="Theme.Sample" parent="Theme.Base" /> + + <style name="AppTheme" parent="Theme.Sample" /> + <!-- Widget styling --> + + <style name="Widget" /> + + <style name="Widget.SampleMessage"> + <item name="android:textAppearance">?android:textAppearanceMedium</item> + <item name="android:lineSpacingMultiplier">1.1</item> + </style> + + <style name="Widget.SampleMessageTile"> + <item name="android:background">@drawable/tile</item> + <item name="android:shadowColor">#7F000000</item> + <item name="android:shadowDy">-3.5</item> + <item name="android:shadowRadius">2</item> + </style> + +</resources> diff --git a/prebuilts/gradle/PermissionRequest/Application/tests/src/com/example/android/permissionrequest/test/SampleTests.java b/prebuilts/gradle/PermissionRequest/Application/tests/src/com/example/android/permissionrequest/test/SampleTests.java new file mode 100644 index 00000000..a88589b3 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/Application/tests/src/com/example/android/permissionrequest/test/SampleTests.java @@ -0,0 +1,196 @@ +/* +* 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.permissionrequest.test; + +import android.graphics.Rect; +import android.os.SystemClock; +import android.test.ActivityInstrumentationTestCase2; +import android.view.MotionEvent; +import android.view.View; +import android.webkit.ConsoleMessage; +import android.webkit.WebView; + +import com.example.android.permissionrequest.ConfirmationDialogFragment; +import com.example.android.permissionrequest.MainActivity; +import com.example.android.permissionrequest.PermissionRequestFragment; +import com.example.android.permissionrequest.R; + +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * Tests for PermissionRequest sample. + */ +public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> { + + private MainActivity mTestActivity; + private PermissionRequestFragment mTestFragment; + + public SampleTests() { + super(MainActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + mTestActivity = getActivity(); + mTestFragment = (PermissionRequestFragment) + mTestActivity.getSupportFragmentManager().getFragments().get(1); + } + + /** + * Test if the test fixture has been set up correctly. + */ + public void testPreconditions() { + assertNotNull("mTestActivity is null", mTestActivity); + assertNotNull("mTestFragment is null", mTestFragment); + } + + public void testWebView_grantPermissionRequest() throws Throwable { + View view = mTestFragment.getView(); + assertNotNull(view); + final WebView webView = (WebView) view.findViewById(R.id.web_view); + assertNotNull(webView); + + final ConsoleMonitor monitor = new ConsoleMonitor(); + mTestFragment.setConsoleMonitor(monitor); + + // Click the "Start" button + assertTrue(monitor.waitForKeyword("Page loaded", 2000)); + clickToggle(webView); + + // Wait for the dialog + ConfirmationDialogFragment dialogFragment = waitForDialog(); + assertNotNull(dialogFragment); + + // Click "Allow" + monitor.reset(); + clickDialogButton(dialogFragment, android.R.id.button1); + + assertTrue(monitor.waitForKeyword("Started", 2000)); + + // Click the "Stop" button + monitor.reset(); + clickToggle(webView); + assertTrue(monitor.waitForKeyword("Stopped", 2000)); + + // Click the "Start" button + monitor.reset(); + clickToggle(webView); + + // Wait for the dialog + dialogFragment = waitForDialog(); + assertNotNull(dialogFragment); + + // Click "Deny" + monitor.reset(); + clickDialogButton(dialogFragment, android.R.id.button2); + assertTrue(monitor.waitForKeyword("Denied", 2000)); + } + + /** + * Click the Start/Stop button. + * + * @param webView The {@link WebView}. + * @throws Throwable + */ + private void clickToggle(final WebView webView) throws Throwable { + runTestOnUiThread(new Runnable() { + @Override + public void run() { + Rect rect = new Rect(); + webView.getHitRect(rect); + int x = rect.width() / 2; + int y = 100; + MotionEvent event = MotionEvent.obtain(SystemClock.uptimeMillis(), + SystemClock.uptimeMillis() + 100, MotionEvent.ACTION_DOWN, x, y, 0); + webView.dispatchTouchEvent(event); + event = MotionEvent.obtain(SystemClock.uptimeMillis(), + SystemClock.uptimeMillis() + 100, MotionEvent.ACTION_UP, x, y, 0); + webView.dispatchTouchEvent(event); + } + }); + } + + /** + * Wait for the dialog for 2 seconds (100 ms * 20 trials). + * + * @return The dialog. + * @throws InterruptedException + */ + private ConfirmationDialogFragment waitForDialog() throws InterruptedException { + int count = 20; + ConfirmationDialogFragment dialog = null; + while (0 < count) { + dialog = (ConfirmationDialogFragment) mTestFragment.getChildFragmentManager() + .findFragmentByTag("dialog"); + if (null != dialog) { + break; + } + Thread.sleep(100); + --count; + } + return dialog; + } + + /** + * Press the specified button on the dialog. + * + * @param dialogFragment The dialog. + * @param buttonId The resource ID of the button to press. + * @throws Throwable + */ + private void clickDialogButton(final ConfirmationDialogFragment dialogFragment, + final int buttonId) throws Throwable { + runTestOnUiThread(new Runnable() { + @Override + public void run() { + dialogFragment.getDialog().findViewById(buttonId).performClick(); + assertFalse(dialogFragment.isVisible()); + } + }); + } + + private class ConsoleMonitor implements PermissionRequestFragment.ConsoleMonitor { + + private final ConcurrentLinkedQueue<String> mMessages = new ConcurrentLinkedQueue<String>(); + + @Override + public void onConsoleMessage(ConsoleMessage message) { + mMessages.offer(message.message()); + } + + public boolean waitForKeyword(String keyword, long timeoutMs) throws InterruptedException { + long time = 0; + while (time < timeoutMs) { + String message; + while (null != (message = mMessages.poll())) { + if (message.contains(keyword)) { + return true; + } + } + Thread.sleep(100); + time += 100; + } + return false; + } + + public void reset() { + mMessages.clear(); + } + + } + +} diff --git a/prebuilts/gradle/PermissionRequest/CONTRIBUTING.md b/prebuilts/gradle/PermissionRequest/CONTRIBUTING.md new file mode 100644 index 00000000..faa8b5c6 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/CONTRIBUTING.md @@ -0,0 +1,35 @@ +# How to become a contributor and submit your own code + +## Contributor License Agreements + +We'd love to accept your sample apps and patches! Before we can take them, we +have to jump a couple of legal hurdles. + +Please fill out either the individual or corporate Contributor License Agreement (CLA). + + * If you are an individual writing original source code and you're sure you + own the intellectual property, then you'll need to sign an [individual CLA] + (https://cla.developers.google.com). + * If you work for a company that wants to allow you to contribute your work, + then you'll need to sign a [corporate CLA] + (https://cla.developers.google.com). + +Follow either of the two links above to access the appropriate CLA and +instructions for how to sign and return it. Once we receive it, we'll be able to +accept your pull requests. + +## Contributing A Patch + +1. Submit an issue describing your proposed change to the repo in question. +1. The repo owner will respond to your issue promptly. +1. If your proposed change is accepted, and you haven't already done so, sign a + Contributor License Agreement (see details above). +1. Fork the desired repo, develop and test your code changes. +1. Ensure that your code adheres to the existing style in the sample to which + you are contributing. Refer to the + [Android Code Style Guide] + (https://source.android.com/source/code-style.html) for the + recommended coding standards for this organization. +1. Ensure that your code has an appropriate set of unit tests which all pass. +1. Submit a pull request. + diff --git a/prebuilts/gradle/PermissionRequest/LICENSE b/prebuilts/gradle/PermissionRequest/LICENSE new file mode 100644 index 00000000..1af981f5 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + 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. diff --git a/prebuilts/gradle/PermissionRequest/NOTICE b/prebuilts/gradle/PermissionRequest/NOTICE new file mode 100644 index 00000000..7eede3de --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/NOTICE @@ -0,0 +1,15 @@ +This sample uses the following software: + +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. diff --git a/prebuilts/gradle/PermissionRequest/README.md b/prebuilts/gradle/PermissionRequest/README.md new file mode 100644 index 00000000..841159cb --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/README.md @@ -0,0 +1,93 @@ +Android PermissionRequest Sample +=================================== + +This sample demonstrates how to use the PermissionRequest API to +securely provide access to restricted system features (such as a +camera or microphone) from within a WebView. In this example, a dialog +is created to allow users to explicitly approve or reject each +request. + +Introduction +------------ + +PermissionRequest can be used by setting up a custom WebChromeClient. + +```java +mWebView.setWebChromeClient(mWebChromeClient); +``` + +In you WebChromeClient implementation, you need to override +[onPermissionRequest][1]. This method is called when the web content +is requesting permission to access some resources, providing an +opportunity to approve or reject the request. In this implementation, +we display a dialog to allow the user to approve or reject any +request. In other applications, you may want to implement a whitelist +of allowed APIs. Also, override [onPermissionRequestCanceled][2] for +handling cancellation of the PermissionRequest by the web content. + +When the user confirms or denies the request, you can respond back to +the web content by [grant][3] or [deny][4] respectively. + +```java +mPermissionRequest.grant(mPermissionRequest.getResources()); +``` + +This sample provides the web content from the assets folder in the +app. Since WebView is not allowed to use getUserMedia from a "file://" +URL, the app uses the SimpleWebServer class to provide the content via +"http://localhost". + +[1]: http://developer.android.com/reference/android/webkit/WebChromeClient.html#onPermissionRequest(android.webkit.PermissionRequest) +[2]: http://developer.android.com/reference/android/webkit/WebChromeClient.html#onPermissionRequestCanceled(android.webkit.PermissionRequest) +[3]: http://developer.android.com/reference/android/webkit/PermissionRequest.html#grant(java.lang.String[]) +[4]: http://developer.android.com/reference/android/webkit/PermissionRequest.html#deny() + +Pre-requisites +-------------- + +- Android SDK v21 +- Android Build Tools v21.1.1 +- Android Support Repository + +Screenshots +------------- + +<img src="screenshots/main.png" height="400" alt="Screenshot"/> + +Getting Started +--------------- + +This sample uses the Gradle build system. To build this project, use the +"gradlew build" command or use "Import Project" in Android Studio. + +Support +------- + +- Google+ Community: https://plus.google.com/communities/105153134372062985968 +- Stack Overflow: http://stackoverflow.com/questions/tagged/android + +If you've found an error in this sample, please file an issue: +https://github.com/googlesamples/android-PermissionRequest + +Patches are encouraged, and may be submitted by forking this project and +submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details. + +License +------- + +Copyright 2014 The Android Open Source Project, Inc. + +Licensed to the Apache Software Foundation (ASF) under one or more contributor +license agreements. See the NOTICE file distributed with this work for +additional information regarding copyright ownership. The ASF licenses this +file to you 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. diff --git a/prebuilts/gradle/PermissionRequest/build.gradle b/prebuilts/gradle/PermissionRequest/build.gradle new file mode 100644 index 00000000..1dac6def --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/build.gradle @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/prebuilts/gradle/PermissionRequest/gradle/wrapper/gradle-wrapper.jar b/prebuilts/gradle/PermissionRequest/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 00000000..8c0fb64a --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/gradle/wrapper/gradle-wrapper.jar diff --git a/prebuilts/gradle/PermissionRequest/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/PermissionRequest/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..4eda7c51 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Dec 09 18:05:08 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/prebuilts/gradle/PermissionRequest/gradlew b/prebuilts/gradle/PermissionRequest/gradlew new file mode 100755 index 00000000..91a7e269 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/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/prebuilts/gradle/PermissionRequest/gradlew.bat b/prebuilts/gradle/PermissionRequest/gradlew.bat new file mode 100644 index 00000000..aec99730 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/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/prebuilts/gradle/PermissionRequest/screenshots/icon_web.png b/prebuilts/gradle/PermissionRequest/screenshots/icon_web.png Binary files differnew file mode 100644 index 00000000..4a8c2f10 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/screenshots/icon_web.png diff --git a/prebuilts/gradle/PermissionRequest/screenshots/image1.png b/prebuilts/gradle/PermissionRequest/screenshots/image1.png Binary files differnew file mode 100644 index 00000000..9ce9fc85 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/screenshots/image1.png diff --git a/prebuilts/gradle/PermissionRequest/screenshots/image2.png b/prebuilts/gradle/PermissionRequest/screenshots/image2.png Binary files differnew file mode 100644 index 00000000..e919bd1a --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/screenshots/image2.png diff --git a/prebuilts/gradle/PermissionRequest/settings.gradle b/prebuilts/gradle/PermissionRequest/settings.gradle new file mode 100644 index 00000000..9464a359 --- /dev/null +++ b/prebuilts/gradle/PermissionRequest/settings.gradle @@ -0,0 +1 @@ +include 'Application' diff --git a/prebuilts/gradle/RecipeAssistant/Application/build.gradle b/prebuilts/gradle/RecipeAssistant/Application/build.gradle index f3cacbe1..3859b3ee 100644 --- a/prebuilts/gradle/RecipeAssistant/Application/build.gradle +++ b/prebuilts/gradle/RecipeAssistant/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/RecyclerView/Application/build.gradle b/prebuilts/gradle/RecyclerView/Application/build.gradle index 616b2413..2dcaf29f 100644 --- a/prebuilts/gradle/RecyclerView/Application/build.gradle +++ b/prebuilts/gradle/RecyclerView/Application/build.gradle @@ -17,11 +17,11 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" - compile "com.android.support:recyclerview-v7:+" + compile "com.android.support:recyclerview-v7:21.0.2" } // The sample build uses multiple directories to diff --git a/prebuilts/gradle/RecyclerView/Application/src/main/java/com/example/android/recyclerview/RecyclerViewFragment.java b/prebuilts/gradle/RecyclerView/Application/src/main/java/com/example/android/recyclerview/RecyclerViewFragment.java index 019657ff..1c0fdede 100644 --- a/prebuilts/gradle/RecyclerView/Application/src/main/java/com/example/android/recyclerview/RecyclerViewFragment.java +++ b/prebuilts/gradle/RecyclerView/Application/src/main/java/com/example/android/recyclerview/RecyclerViewFragment.java @@ -80,7 +80,7 @@ public class RecyclerViewFragment extends Fragment { if (savedInstanceState != null) { // Restore saved layout manager type. mCurrentLayoutManagerType = (LayoutManagerType) savedInstanceState - .getSerializable(LAYOUT_MANAGER_KEY); + .getSerializable(KEY_LAYOUT_MANAGER); } setRecyclerViewLayoutManager(mCurrentLayoutManagerType); @@ -143,7 +143,7 @@ public class RecyclerViewFragment extends Fragment { @Override public void onSaveInstanceState(Bundle savedInstanceState) { // Save currently selected layout manager. - savedInstanceState.putSerializable(LAYOUT_MANAGER_KEY, mCurrentLayoutManagerType); + savedInstanceState.putSerializable(KEY_LAYOUT_MANAGER, mCurrentLayoutManagerType); super.onSaveInstanceState(savedInstanceState); } diff --git a/prebuilts/gradle/RenderScriptIntrinsic/Application/build.gradle b/prebuilts/gradle/RenderScriptIntrinsic/Application/build.gradle index fd0410df..7d56123c 100644 --- a/prebuilts/gradle/RenderScriptIntrinsic/Application/build.gradle +++ b/prebuilts/gradle/RenderScriptIntrinsic/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" compile files('renderscript-v8.jar') } diff --git a/prebuilts/gradle/RepeatingAlarm/Application/build.gradle b/prebuilts/gradle/RepeatingAlarm/Application/build.gradle index 05020be5..76169dee 100644 --- a/prebuilts/gradle/RepeatingAlarm/Application/build.gradle +++ b/prebuilts/gradle/RepeatingAlarm/Application/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" + compile "com.android.support:support-v4:21.0.2" } diff --git a/prebuilts/gradle/RevealEffectBasic/Application/build.gradle b/prebuilts/gradle/RevealEffectBasic/Application/build.gradle index 20561c2a..71ddf508 100644 --- a/prebuilts/gradle/RevealEffectBasic/Application/build.gradle +++ b/prebuilts/gradle/RevealEffectBasic/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/ScreenCapture/.google/packaging.yaml b/prebuilts/gradle/ScreenCapture/.google/packaging.yaml new file mode 100644 index 00000000..d33e2776 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/.google/packaging.yaml @@ -0,0 +1,18 @@ +# GOOGLE SAMPLE PACKAGING DATA +# +# This file is used by Google as part of our samples packaging process. +# End users may safely ignore this file. It has no relevance to other systems. +--- +status: PUBLISHED +technologies: [Android] +categories: [Media] +languages: [Java] +solutions: [Mobile] +github: android-ScreenCapture +level: INTERMEDIATE +icon: screenshots/icon-web.png +apiRefs: + - android:android.media.projection.MediaProjection + - android:android.media.projection.MediaProjectionManager + - android:android.hardware.display.VirtualDisplay +license: apache2 diff --git a/prebuilts/gradle/ScreenCapture/Application/build.gradle b/prebuilts/gradle/ScreenCapture/Application/build.gradle new file mode 100644 index 00000000..71ddf508 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/build.gradle @@ -0,0 +1,70 @@ +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:1.0.0' + } +} + +apply plugin: 'com.android.application' + +repositories { + jcenter() +} + + +dependencies { + + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" + +} + +// The sample build uses multiple directories to +// keep boilerplate and common code separate from +// the main sample code. +List<String> dirs = [ + 'main', // main sample code; look here for the interesting stuff. + 'common', // components that are reused by multiple samples + 'template'] // boilerplate code that is generated by the sample template process + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 21 + targetSdkVersion 21 + } + + sourceSets { + main { + dirs.each { dir -> + java.srcDirs "src/${dir}/java" + res.srcDirs "src/${dir}/res" + } + } + androidTest.setRoot('tests') + androidTest.java.srcDirs = ['tests/src'] + + } + +} + + + + + + + + + + + + + + + diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/AndroidManifest.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/AndroidManifest.xml new file mode 100644 index 00000000..2dfd4f70 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ +<?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.screencapture"> + + <application android:allowBackup="true" + android:label="@string/app_name" + android:icon="@drawable/ic_launcher" + android:theme="@style/AppTheme"> + + <activity android:name=".MainActivity" + 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/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/activities/SampleActivityBase.java b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/activities/SampleActivityBase.java new file mode 100644 index 00000000..3228927b --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/activities/SampleActivityBase.java @@ -0,0 +1,52 @@ +/* +* 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. +*/ + +package com.example.android.common.activities; + +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; + +import com.example.android.common.logger.Log; +import com.example.android.common.logger.LogWrapper; + +/** + * Base launcher activity, to handle most of the common plumbing for samples. + */ +public class SampleActivityBase extends FragmentActivity { + + public static final String TAG = "SampleActivityBase"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + protected void onStart() { + super.onStart(); + initializeLogging(); + } + + /** Set up targets to receive log data */ + public void initializeLogging() { + // Using Log, front-end to the logging chain, emulates android.util.log method signatures. + // Wraps Android's native log framework + LogWrapper logWrapper = new LogWrapper(); + Log.setLogNode(logWrapper); + + Log.i(TAG, "Ready"); + } +} diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/Log.java b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/Log.java new file mode 100644 index 00000000..17503c56 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/Log.java @@ -0,0 +1,236 @@ +/* + * Copyright (C) 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. + */ +package com.example.android.common.logger; + +/** + * Helper class for a list (or tree) of LoggerNodes. + * + * <p>When this is set as the head of the list, + * an instance of it can function as a drop-in replacement for {@link android.util.Log}. + * Most of the methods in this class server only to map a method call in Log to its equivalent + * in LogNode.</p> + */ +public class Log { + // Grabbing the native values from Android's native logging facilities, + // to make for easy migration and interop. + public static final int NONE = -1; + public static final int VERBOSE = android.util.Log.VERBOSE; + public static final int DEBUG = android.util.Log.DEBUG; + public static final int INFO = android.util.Log.INFO; + public static final int WARN = android.util.Log.WARN; + public static final int ERROR = android.util.Log.ERROR; + public static final int ASSERT = android.util.Log.ASSERT; + + // Stores the beginning of the LogNode topology. + private static LogNode mLogNode; + + /** + * Returns the next LogNode in the linked list. + */ + public static LogNode getLogNode() { + return mLogNode; + } + + /** + * Sets the LogNode data will be sent to. + */ + public static void setLogNode(LogNode node) { + mLogNode = node; + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void println(int priority, String tag, String msg, Throwable tr) { + if (mLogNode != null) { + mLogNode.println(priority, tag, msg, tr); + } + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + */ + public static void println(int priority, String tag, String msg) { + println(priority, tag, msg, null); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void v(String tag, String msg, Throwable tr) { + println(VERBOSE, tag, msg, tr); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void v(String tag, String msg) { + v(tag, msg, null); + } + + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void d(String tag, String msg, Throwable tr) { + println(DEBUG, tag, msg, tr); + } + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void d(String tag, String msg) { + d(tag, msg, null); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void i(String tag, String msg, Throwable tr) { + println(INFO, tag, msg, tr); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void i(String tag, String msg) { + i(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, String msg, Throwable tr) { + println(WARN, tag, msg, tr); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void w(String tag, String msg) { + w(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, Throwable tr) { + w(tag, null, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void e(String tag, String msg, Throwable tr) { + println(ERROR, tag, msg, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void e(String tag, String msg) { + e(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, String msg, Throwable tr) { + println(ASSERT, tag, msg, tr); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void wtf(String tag, String msg) { + wtf(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, Throwable tr) { + wtf(tag, null, tr); + } +} diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/LogFragment.java b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/LogFragment.java new file mode 100644 index 00000000..b302acd4 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/LogFragment.java @@ -0,0 +1,109 @@ +/* +* 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. +*/ +/* + * 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. + */ + +package com.example.android.common.logger; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ScrollView; + +/** + * Simple fraggment which contains a LogView and uses is to output log data it receives + * through the LogNode interface. + */ +public class LogFragment extends Fragment { + + private LogView mLogView; + private ScrollView mScrollView; + + public LogFragment() {} + + public View inflateViews() { + mScrollView = new ScrollView(getActivity()); + ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mScrollView.setLayoutParams(scrollParams); + + mLogView = new LogView(getActivity()); + ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams); + logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + mLogView.setLayoutParams(logParams); + mLogView.setClickable(true); + mLogView.setFocusable(true); + mLogView.setTypeface(Typeface.MONOSPACE); + + // Want to set padding as 16 dips, setPadding takes pixels. Hooray math! + int paddingDips = 16; + double scale = getResources().getDisplayMetrics().density; + int paddingPixels = (int) ((paddingDips * (scale)) + .5); + mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels); + mLogView.setCompoundDrawablePadding(paddingPixels); + + mLogView.setGravity(Gravity.BOTTOM); + mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium); + + mScrollView.addView(mLogView); + return mScrollView; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View result = inflateViews(); + + mLogView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + mScrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + }); + return result; + } + + public LogView getLogView() { + return mLogView; + } +}
\ No newline at end of file diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/LogNode.java b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/LogNode.java new file mode 100644 index 00000000..bc37cabc --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/LogNode.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 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.common.logger; + +/** + * Basic interface for a logging system that can output to one or more targets. + * Note that in addition to classes that will output these logs in some format, + * one can also implement this interface over a filter and insert that in the chain, + * such that no targets further down see certain data, or see manipulated forms of the data. + * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data + * it received to HTML and sent it along to the next node in the chain, without printing it + * anywhere. + */ +public interface LogNode { + + /** + * Instructs first LogNode in the list to print the log data provided. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public void println(int priority, String tag, String msg, Throwable tr); + +} diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/LogView.java b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/LogView.java new file mode 100644 index 00000000..c01542b9 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/LogView.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 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. + */ +package com.example.android.common.logger; + +import android.app.Activity; +import android.content.Context; +import android.util.*; +import android.widget.TextView; + +/** Simple TextView which is used to output log data received through the LogNode interface. +*/ +public class LogView extends TextView implements LogNode { + + public LogView(Context context) { + super(context); + } + + public LogView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LogView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Formats the log data and prints it out to the LogView. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + + + String priorityStr = null; + + // For the purposes of this View, we want to print the priority as readable text. + switch(priority) { + case android.util.Log.VERBOSE: + priorityStr = "VERBOSE"; + break; + case android.util.Log.DEBUG: + priorityStr = "DEBUG"; + break; + case android.util.Log.INFO: + priorityStr = "INFO"; + break; + case android.util.Log.WARN: + priorityStr = "WARN"; + break; + case android.util.Log.ERROR: + priorityStr = "ERROR"; + break; + case android.util.Log.ASSERT: + priorityStr = "ASSERT"; + break; + default: + break; + } + + // Handily, the Log class has a facility for converting a stack trace into a usable string. + String exceptionStr = null; + if (tr != null) { + exceptionStr = android.util.Log.getStackTraceString(tr); + } + + // Take the priority, tag, message, and exception, and concatenate as necessary + // into one usable line of text. + final StringBuilder outputBuilder = new StringBuilder(); + + String delimiter = "\t"; + appendIfNotNull(outputBuilder, priorityStr, delimiter); + appendIfNotNull(outputBuilder, tag, delimiter); + appendIfNotNull(outputBuilder, msg, delimiter); + appendIfNotNull(outputBuilder, exceptionStr, delimiter); + + // In case this was originally called from an AsyncTask or some other off-UI thread, + // make sure the update occurs within the UI thread. + ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() { + @Override + public void run() { + // Display the text we just generated within the LogView. + appendToLog(outputBuilder.toString()); + } + }))); + + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } + + public LogNode getNext() { + return mNext; + } + + public void setNext(LogNode node) { + mNext = node; + } + + /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since + * the logger takes so many arguments that might be null, this method helps cut out some of the + * agonizing tedium of writing the same 3 lines over and over. + * @param source StringBuilder containing the text to append to. + * @param addStr The String to append + * @param delimiter The String to separate the source and appended strings. A tab or comma, + * for instance. + * @return The fully concatenated String as a StringBuilder + */ + private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) { + if (addStr != null) { + if (addStr.length() == 0) { + delimiter = ""; + } + + return source.append(addStr).append(delimiter); + } + return source; + } + + // The next LogNode in the chain. + LogNode mNext; + + /** Outputs the string as a new line of log data in the LogView. */ + public void appendToLog(String s) { + append("\n" + s); + } + + +} diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/LogWrapper.java b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/LogWrapper.java new file mode 100644 index 00000000..16a9e7ba --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/LogWrapper.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 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.common.logger; + +import android.util.Log; + +/** + * Helper class which wraps Android's native Log utility in the Logger interface. This way + * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously. + */ +public class LogWrapper implements LogNode { + + // For piping: The next node to receive Log data after this one has done its work. + private LogNode mNext; + + /** + * Returns the next LogNode in the linked list. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + + /** + * Prints data out to the console using Android's native log mechanism. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + // There actually are log methods that don't take a msg parameter. For now, + // if that's the case, just convert null to the empty string and move on. + String useMsg = msg; + if (useMsg == null) { + useMsg = ""; + } + + // If an exeption was provided, convert that exception to a usable string and attach + // it to the end of the msg method. + if (tr != null) { + msg += "\n" + Log.getStackTraceString(tr); + } + + // This is functionally identical to Log.x(tag, useMsg); + // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg) + Log.println(priority, tag, useMsg); + + // If this isn't the last node in the chain, move things along. + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } +} diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.java b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.java new file mode 100644 index 00000000..19967dcd --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 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. + */ +package com.example.android.common.logger; + +/** + * Simple {@link LogNode} filter, removes everything except the message. + * Useful for situations like on-screen log output where you don't want a lot of metadata displayed, + * just easy-to-read message updates as they're happening. + */ +public class MessageOnlyLogFilter implements LogNode { + + LogNode mNext; + + /** + * Takes the "next" LogNode as a parameter, to simplify chaining. + * + * @param next The next LogNode in the pipeline. + */ + public MessageOnlyLogFilter(LogNode next) { + mNext = next; + } + + public MessageOnlyLogFilter() { + } + + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + if (mNext != null) { + getNext().println(Log.NONE, null, msg, null); + } + } + + /** + * Returns the next LogNode in the chain. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + +} diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/screencapture/MainActivity.java b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/screencapture/MainActivity.java new file mode 100644 index 00000000..67ae9e89 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/screencapture/MainActivity.java @@ -0,0 +1,109 @@ +/* +* 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. +*/ + +package com.example.android.screencapture; + +import android.os.Bundle; +import android.support.v4.app.FragmentTransaction; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.ViewAnimator; + +import com.example.android.common.activities.SampleActivityBase; +import com.example.android.common.logger.Log; +import com.example.android.common.logger.LogFragment; +import com.example.android.common.logger.LogWrapper; +import com.example.android.common.logger.MessageOnlyLogFilter; + +/** + * A simple launcher activity containing a summary sample description, sample log and a custom + * {@link android.support.v4.app.Fragment} which can display a view. + * <p> + * For devices with displays with a width of 720dp or greater, the sample log is always visible, + * on other devices it's visibility is controlled by an item on the Action Bar. + */ +public class MainActivity extends SampleActivityBase { + + public static final String TAG = "MainActivity"; + + // Whether the Log Fragment is currently shown + private boolean mLogShown; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + if (savedInstanceState == null) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + ScreenCaptureFragment fragment = new ScreenCaptureFragment(); + transaction.replace(R.id.sample_content_fragment, fragment); + transaction.commit(); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.main, menu); + return true; + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + MenuItem logToggle = menu.findItem(R.id.menu_toggle_log); + logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator); + logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log); + + return super.onPrepareOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch(item.getItemId()) { + case R.id.menu_toggle_log: + mLogShown = !mLogShown; + ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output); + if (mLogShown) { + output.setDisplayedChild(1); + } else { + output.setDisplayedChild(0); + } + supportInvalidateOptionsMenu(); + return true; + } + return super.onOptionsItemSelected(item); + } + + /** Create a chain of targets that will receive log data */ + @Override + public void initializeLogging() { + // Wraps Android's native log framework. + LogWrapper logWrapper = new LogWrapper(); + // Using Log, front-end to the logging chain, emulates android.util.log method signatures. + Log.setLogNode(logWrapper); + + // Filter strips out everything except the message text. + MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter(); + logWrapper.setNext(msgFilter); + + // On screen logging via a fragment with a TextView. + LogFragment logFragment = (LogFragment) getSupportFragmentManager() + .findFragmentById(R.id.log_fragment); + msgFilter.setNext(logFragment.getLogView()); + + Log.i(TAG, "Ready"); + } +} diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/screencapture/ScreenCaptureFragment.java b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/screencapture/ScreenCaptureFragment.java new file mode 100644 index 00000000..f1345792 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/java/com/example/android/screencapture/ScreenCaptureFragment.java @@ -0,0 +1,202 @@ +/* + * 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.screencapture; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.hardware.display.DisplayManager; +import android.hardware.display.VirtualDisplay; +import android.media.projection.MediaProjection; +import android.media.projection.MediaProjectionManager; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.util.DisplayMetrics; +import android.view.LayoutInflater; +import android.view.Surface; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.Toast; + +import com.example.android.common.logger.Log; + +/** + * Provides UI for the screen capture. + */ +public class ScreenCaptureFragment extends Fragment implements View.OnClickListener { + + private static final String TAG = "ScreenCaptureFragment"; + + private static final String STATE_RESULT_CODE = "result_code"; + private static final String STATE_RESULT_DATA = "result_data"; + + private static final int REQUEST_MEDIA_PROJECTION = 1; + + private int mScreenDensity; + + private int mResultCode; + private Intent mResultData; + + private Surface mSurface; + private MediaProjection mMediaProjection; + private VirtualDisplay mVirtualDisplay; + private MediaProjectionManager mMediaProjectionManager; + private Button mButtonToggle; + private SurfaceView mSurfaceView; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (savedInstanceState != null) { + mResultCode = savedInstanceState.getInt(STATE_RESULT_CODE); + mResultData = savedInstanceState.getParcelable(STATE_RESULT_DATA); + } + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_screen_capture, container, false); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + mSurfaceView = (SurfaceView) view.findViewById(R.id.surface); + mSurface = mSurfaceView.getHolder().getSurface(); + mButtonToggle = (Button) view.findViewById(R.id.toggle); + mButtonToggle.setOnClickListener(this); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + Activity activity = getActivity(); + DisplayMetrics metrics = new DisplayMetrics(); + activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); + mScreenDensity = metrics.densityDpi; + mMediaProjectionManager = (MediaProjectionManager) + activity.getSystemService(Context.MEDIA_PROJECTION_SERVICE); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (mResultData != null) { + outState.putInt(STATE_RESULT_CODE, mResultCode); + outState.putParcelable(STATE_RESULT_DATA, mResultData); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.toggle: + if (mVirtualDisplay == null) { + startScreenCapture(); + } else { + stopScreenCapture(); + } + break; + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_MEDIA_PROJECTION) { + if (resultCode != Activity.RESULT_OK) { + Log.i(TAG, "User cancelled"); + Toast.makeText(getActivity(), R.string.user_cancelled, Toast.LENGTH_SHORT).show(); + return; + } + Activity activity = getActivity(); + if (activity == null) { + return; + } + Log.i(TAG, "Starting screen capture"); + mResultCode = resultCode; + mResultData = data; + setUpMediaProjection(); + setUpVirtualDisplay(); + } + } + + @Override + public void onPause() { + super.onPause(); + stopScreenCapture(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + tearDownMediaProjection(); + } + + private void setUpMediaProjection() { + mMediaProjection = mMediaProjectionManager.getMediaProjection(mResultCode, mResultData); + } + + private void tearDownMediaProjection() { + if (mMediaProjection != null) { + mMediaProjection.stop(); + mMediaProjection = null; + } + } + + private void startScreenCapture() { + Activity activity = getActivity(); + if (mSurface == null || activity == null) { + return; + } + if (mMediaProjection != null) { + setUpVirtualDisplay(); + } else if (mResultCode != 0 && mResultData != null) { + setUpMediaProjection(); + setUpVirtualDisplay(); + } else { + Log.i(TAG, "Requesting confirmation"); + // This initiates a prompt dialog for the user to confirm screen projection. + startActivityForResult( + mMediaProjectionManager.createScreenCaptureIntent(), + REQUEST_MEDIA_PROJECTION); + } + } + + private void setUpVirtualDisplay() { + Log.i(TAG, "Setting up a VirtualDisplay: " + + mSurfaceView.getWidth() + "x" + mSurfaceView.getHeight() + + " (" + mScreenDensity + ")"); + mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCapture", + mSurfaceView.getWidth(), mSurfaceView.getHeight(), mScreenDensity, + DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, + mSurface, null, null); + mButtonToggle.setText(R.string.stop); + } + + private void stopScreenCapture() { + if (mVirtualDisplay == null) { + return; + } + mVirtualDisplay.release(); + mVirtualDisplay = null; + mButtonToggle.setText(R.string.start); + } + +} diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-hdpi/ic_launcher.png b/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..69d518c6 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-hdpi/tile.9.png b/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-hdpi/tile.9.png Binary files differnew file mode 100644 index 00000000..13586288 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-hdpi/tile.9.png diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-mdpi/ic_launcher.png b/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..c107f97a --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..a4d33c2c --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..fe23a075 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/layout-w720dp/activity_main.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/res/layout-w720dp/activity_main.xml new file mode 100755 index 00000000..c9a52f62 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/layout-w720dp/activity_main.xml @@ -0,0 +1,73 @@ +<!-- + 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. + --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:id="@+id/sample_main_layout"> + + <LinearLayout + android:id="@+id/sample_output" + android:layout_width="0px" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="vertical"> + + <FrameLayout + style="@style/Widget.SampleMessageTile" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + style="@style/Widget.SampleMessage" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingLeft="@dimen/margin_medium" + android:paddingRight="@dimen/margin_medium" + android:paddingTop="@dimen/margin_large" + android:paddingBottom="@dimen/margin_large" + android:text="@string/intro_message" /> + </FrameLayout> + + <View + android:layout_width="match_parent" + android:layout_height="1dp" + android:background="@android:color/darker_gray" /> + + <fragment + android:name="com.example.android.common.logger.LogFragment" + android:id="@+id/log_fragment" + android:layout_width="match_parent" + android:layout_height="0px" + android:layout_weight="1" /> + + </LinearLayout> + + <View + android:layout_width="1dp" + android:layout_height="match_parent" + android:background="@android:color/darker_gray" /> + + <FrameLayout + android:id="@+id/sample_content_fragment" + android:layout_weight="2" + android:layout_width="0px" + android:layout_height="match_parent" /> + +</LinearLayout> + + diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/layout/activity_main.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/res/layout/activity_main.xml new file mode 100755 index 00000000..1ae4f981 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/layout/activity_main.xml @@ -0,0 +1,65 @@ +<!-- + 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. + --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:id="@+id/sample_main_layout"> + + <ViewAnimator + android:id="@+id/sample_output" + android:layout_width="match_parent" + android:layout_height="0px" + android:layout_weight="1"> + + <ScrollView + style="@style/Widget.SampleMessageTile" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <TextView + style="@style/Widget.SampleMessage" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingLeft="@dimen/horizontal_page_margin" + android:paddingRight="@dimen/horizontal_page_margin" + android:paddingTop="@dimen/vertical_page_margin" + android:paddingBottom="@dimen/vertical_page_margin" + android:text="@string/intro_message" /> + </ScrollView> + + <fragment + android:name="com.example.android.common.logger.LogFragment" + android:id="@+id/log_fragment" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + </ViewAnimator> + + <View + android:layout_width="match_parent" + android:layout_height="1dp" + android:background="@android:color/darker_gray" /> + + <FrameLayout + android:id="@+id/sample_content_fragment" + android:layout_weight="2" + android:layout_width="match_parent" + android:layout_height="0px" /> + +</LinearLayout> + diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/layout/fragment_screen_capture.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/res/layout/fragment_screen_capture.xml new file mode 100644 index 00000000..343c920c --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/layout/fragment_screen_capture.xml @@ -0,0 +1,36 @@ +<?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:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal"> + + <SurfaceView + android:id="@+id/surface" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1"/> + + <Button + android:id="@+id/toggle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="top" + android:text="@string/start"/> + +</LinearLayout> diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/menu/main.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/res/menu/main.xml new file mode 100644 index 00000000..b49c2c52 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/menu/main.xml @@ -0,0 +1,21 @@ +<!-- + 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. + --> + +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/menu_toggle_log" + android:showAsAction="always" + android:title="@string/sample_show_log" /> +</menu> diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-sw600dp/template-dimens.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-sw600dp/template-dimens.xml new file mode 100644 index 00000000..22074a2b --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-sw600dp/template-dimens.xml @@ -0,0 +1,24 @@ +<!-- + 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. + --> + +<resources> + + <!-- Semantic definitions --> + + <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen> + <dimen name="vertical_page_margin">@dimen/margin_medium</dimen> + +</resources> diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-sw600dp/template-styles.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-sw600dp/template-styles.xml new file mode 100644 index 00000000..03d19741 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-sw600dp/template-styles.xml @@ -0,0 +1,25 @@ +<!-- + 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. + --> + +<resources> + + <style name="Widget.SampleMessage"> + <item name="android:textAppearance">?android:textAppearanceLarge</item> + <item name="android:lineSpacingMultiplier">1.2</item> + <item name="android:shadowDy">-6.5</item> + </style> + +</resources> diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-v11/template-styles.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-v11/template-styles.xml new file mode 100644 index 00000000..8c1ea66f --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-v11/template-styles.xml @@ -0,0 +1,22 @@ +<!-- + 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. + --> + +<resources> + + <!-- Activity themes --> + <style name="Theme.Base" parent="android:Theme.Holo.Light" /> + +</resources> diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-v21/base-colors.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-v21/base-colors.xml new file mode 100644 index 00000000..34c9cd13 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-v21/base-colors.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<resources> + + +</resources> diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-v21/base-template-styles.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-v21/base-template-styles.xml new file mode 100644 index 00000000..0b2948f7 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values-v21/base-template-styles.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<resources> + + <!-- Activity themes --> + <style name="Theme.Base" parent="android:Theme.Material.Light"> + </style> + +</resources> diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/base-strings.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/base-strings.xml new file mode 100644 index 00000000..79880f0b --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/base-strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<resources> + <string name="app_name">ScreenCapture</string> + <string name="intro_message"> + <![CDATA[ + + +This sample demonstrates how to use Media Projection API introduced in Android 5.0 Lollipop. Press +"Start" to start capturing the screen. + + + ]]> + </string> +</resources> diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/fragmentview_strings.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/fragmentview_strings.xml new file mode 100755 index 00000000..7b9d9ec4 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/fragmentview_strings.xml @@ -0,0 +1,19 @@ +<!-- + 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. +--> +<resources> + <string name="sample_show_log">Show Log</string> + <string name="sample_hide_log">Hide Log</string> +</resources> diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/strings.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/strings.xml new file mode 100644 index 00000000..70597e66 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/strings.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> + <string name="start">Start</string> + <string name="stop">Stop</string> + <string name="user_cancelled">User denied screen sharing permission</string> +</resources> diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/template-dimens.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/template-dimens.xml new file mode 100644 index 00000000..39e710b5 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/template-dimens.xml @@ -0,0 +1,32 @@ +<!-- + 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. + --> + +<resources> + + <!-- Define standard dimensions to comply with Holo-style grids and rhythm. --> + + <dimen name="margin_tiny">4dp</dimen> + <dimen name="margin_small">8dp</dimen> + <dimen name="margin_medium">16dp</dimen> + <dimen name="margin_large">32dp</dimen> + <dimen name="margin_huge">64dp</dimen> + + <!-- Semantic definitions --> + + <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen> + <dimen name="vertical_page_margin">@dimen/margin_medium</dimen> + +</resources> diff --git a/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/template-styles.xml b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/template-styles.xml new file mode 100644 index 00000000..6e7d593d --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/src/main/res/values/template-styles.xml @@ -0,0 +1,42 @@ +<!-- + 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. + --> + +<resources> + + <!-- Activity themes --> + + <style name="Theme.Base" parent="android:Theme.Light" /> + + <style name="Theme.Sample" parent="Theme.Base" /> + + <style name="AppTheme" parent="Theme.Sample" /> + <!-- Widget styling --> + + <style name="Widget" /> + + <style name="Widget.SampleMessage"> + <item name="android:textAppearance">?android:textAppearanceMedium</item> + <item name="android:lineSpacingMultiplier">1.1</item> + </style> + + <style name="Widget.SampleMessageTile"> + <item name="android:background">@drawable/tile</item> + <item name="android:shadowColor">#7F000000</item> + <item name="android:shadowDy">-3.5</item> + <item name="android:shadowRadius">2</item> + </style> + +</resources> diff --git a/prebuilts/gradle/ScreenCapture/Application/tests/src/com/example/android/screencapture/test/SampleTests.java b/prebuilts/gradle/ScreenCapture/Application/tests/src/com/example/android/screencapture/test/SampleTests.java new file mode 100644 index 00000000..f3f79975 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/Application/tests/src/com/example/android/screencapture/test/SampleTests.java @@ -0,0 +1,62 @@ +/* + * 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.screencapture.test; + +import android.test.ActivityInstrumentationTestCase2; +import android.view.View; +import android.widget.Button; + +import com.example.android.screencapture.MainActivity; +import com.example.android.screencapture.R; +import com.example.android.screencapture.ScreenCaptureFragment; + +/** + * Tests for ScreenCapture sample. + */ +public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> { + + private MainActivity mTestActivity; + private ScreenCaptureFragment mTestFragment; + + public SampleTests() { + super(MainActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + mTestActivity = getActivity(); + mTestFragment = (ScreenCaptureFragment) + mTestActivity.getSupportFragmentManager().getFragments().get(1); + } + + /** + * Test if the test fixture has been set up correctly. + */ + public void testPreconditions() { + assertNotNull("mTestActivity is null", mTestActivity); + assertNotNull("mTestFragment is null", mTestFragment); + } + + public void testButtonToggle() throws Throwable { + final View view = mTestFragment.getView(); + assertNotNull(view); + final Button buttonToggle = (Button) view.findViewById(R.id.toggle); + assertNotNull(buttonToggle); + } + +} diff --git a/prebuilts/gradle/ScreenCapture/CONTRIBUTING.md b/prebuilts/gradle/ScreenCapture/CONTRIBUTING.md new file mode 100644 index 00000000..faa8b5c6 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/CONTRIBUTING.md @@ -0,0 +1,35 @@ +# How to become a contributor and submit your own code + +## Contributor License Agreements + +We'd love to accept your sample apps and patches! Before we can take them, we +have to jump a couple of legal hurdles. + +Please fill out either the individual or corporate Contributor License Agreement (CLA). + + * If you are an individual writing original source code and you're sure you + own the intellectual property, then you'll need to sign an [individual CLA] + (https://cla.developers.google.com). + * If you work for a company that wants to allow you to contribute your work, + then you'll need to sign a [corporate CLA] + (https://cla.developers.google.com). + +Follow either of the two links above to access the appropriate CLA and +instructions for how to sign and return it. Once we receive it, we'll be able to +accept your pull requests. + +## Contributing A Patch + +1. Submit an issue describing your proposed change to the repo in question. +1. The repo owner will respond to your issue promptly. +1. If your proposed change is accepted, and you haven't already done so, sign a + Contributor License Agreement (see details above). +1. Fork the desired repo, develop and test your code changes. +1. Ensure that your code adheres to the existing style in the sample to which + you are contributing. Refer to the + [Android Code Style Guide] + (https://source.android.com/source/code-style.html) for the + recommended coding standards for this organization. +1. Ensure that your code has an appropriate set of unit tests which all pass. +1. Submit a pull request. + diff --git a/prebuilts/gradle/ScreenCapture/LICENSE b/prebuilts/gradle/ScreenCapture/LICENSE new file mode 100644 index 00000000..1af981f5 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + 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. diff --git a/prebuilts/gradle/ScreenCapture/NOTICE b/prebuilts/gradle/ScreenCapture/NOTICE new file mode 100644 index 00000000..7eede3de --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/NOTICE @@ -0,0 +1,15 @@ +This sample uses the following software: + +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. diff --git a/prebuilts/gradle/ScreenCapture/README.md b/prebuilts/gradle/ScreenCapture/README.md new file mode 100644 index 00000000..ec99efd1 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/README.md @@ -0,0 +1,73 @@ +Android ScreenCapture Sample +=================================== + +This sample demonstrates how to use Media Projection API to capture device screen in real time and +show it on a SurfaceView. + +Introduction +------------ + +Media Projection API lets you capture the current screen through Surface. + +To start media projection, you need to get an instance of [MediaProjection][1]. For this, you have +to call startActivityForResult with an Intent from +[MediaProjectionManager.createScreenCaptureIntent()][2]. This shows a confirmation dialog to the +user. When user confirms it, you will get a result code and data in onActivityResult, so pass those +to [getMediaProjection][3]. + +Once you get a MediaProjection, use [createVirtualDisplay][4] and bind it to a Surface. + +[1]: https://developer.android.com/reference/android/media/projection/MediaProjection.html +[2]: https://developer.android.com/reference/android/media/projection/MediaProjectionManager.html#createScreenCaptureIntent() +[3]: https://developer.android.com/reference/android/media/projection/MediaProjectionManager.html#getMediaProjection(int, android.content.Intent) +[4]: https://developer.android.com/reference/android/media/projection/MediaProjection.html#createVirtualDisplay(java.lang.String, int, int, int, int, android.view.Surface, android.hardware.display.VirtualDisplay.Callback, android.os.Handler) + +Pre-requisites +-------------- + +- Android SDK v21 +- Android Build Tools v21.1.1 +- Android Support Repository + +Screenshots +------------- + +<img src="screenshots/main.png" height="400" alt="Screenshot"/> + +Getting Started +--------------- + +This sample uses the Gradle build system. To build this project, use the +"gradlew build" command or use "Import Project" in Android Studio. + +Support +------- + +- Google+ Community: https://plus.google.com/communities/105153134372062985968 +- Stack Overflow: http://stackoverflow.com/questions/tagged/android + +If you've found an error in this sample, please file an issue: +https://github.com/googlesamples/android-ScreenCapture + +Patches are encouraged, and may be submitted by forking this project and +submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details. + +License +------- + +Copyright 2014 The Android Open Source Project, Inc. + +Licensed to the Apache Software Foundation (ASF) under one or more contributor +license agreements. See the NOTICE file distributed with this work for +additional information regarding copyright ownership. The ASF licenses this +file to you 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. diff --git a/prebuilts/gradle/ScreenCapture/build.gradle b/prebuilts/gradle/ScreenCapture/build.gradle new file mode 100644 index 00000000..1dac6def --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/build.gradle @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/prebuilts/gradle/ScreenCapture/gradle/wrapper/gradle-wrapper.jar b/prebuilts/gradle/ScreenCapture/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 00000000..8c0fb64a --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/gradle/wrapper/gradle-wrapper.jar diff --git a/prebuilts/gradle/ScreenCapture/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/ScreenCapture/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..0c71e760 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Apr 10 15:27:10 PDT 2013 +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/prebuilts/gradle/ScreenCapture/gradlew b/prebuilts/gradle/ScreenCapture/gradlew new file mode 100755 index 00000000..91a7e269 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/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/prebuilts/gradle/ScreenCapture/gradlew.bat b/prebuilts/gradle/ScreenCapture/gradlew.bat new file mode 100644 index 00000000..aec99730 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/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/prebuilts/gradle/ScreenCapture/screenshots/icon-web.png b/prebuilts/gradle/ScreenCapture/screenshots/icon-web.png Binary files differnew file mode 100644 index 00000000..6d41a89f --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/screenshots/icon-web.png diff --git a/prebuilts/gradle/ScreenCapture/screenshots/main.png b/prebuilts/gradle/ScreenCapture/screenshots/main.png Binary files differnew file mode 100644 index 00000000..79fca656 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/screenshots/main.png diff --git a/prebuilts/gradle/ScreenCapture/settings.gradle b/prebuilts/gradle/ScreenCapture/settings.gradle new file mode 100644 index 00000000..9464a359 --- /dev/null +++ b/prebuilts/gradle/ScreenCapture/settings.gradle @@ -0,0 +1 @@ +include 'Application' diff --git a/prebuilts/gradle/SlidingTabsBasic/Application/build.gradle b/prebuilts/gradle/SlidingTabsBasic/Application/build.gradle index 05020be5..76169dee 100644 --- a/prebuilts/gradle/SlidingTabsBasic/Application/build.gradle +++ b/prebuilts/gradle/SlidingTabsBasic/Application/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" + compile "com.android.support:support-v4:21.0.2" } diff --git a/prebuilts/gradle/SlidingTabsColors/Application/build.gradle b/prebuilts/gradle/SlidingTabsColors/Application/build.gradle index 05020be5..76169dee 100644 --- a/prebuilts/gradle/SlidingTabsColors/Application/build.gradle +++ b/prebuilts/gradle/SlidingTabsColors/Application/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" + compile "com.android.support:support-v4:21.0.2" } diff --git a/prebuilts/gradle/StorageClient/Application/build.gradle b/prebuilts/gradle/StorageClient/Application/build.gradle index 05020be5..76169dee 100644 --- a/prebuilts/gradle/StorageClient/Application/build.gradle +++ b/prebuilts/gradle/StorageClient/Application/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" + compile "com.android.support:support-v4:21.0.2" } diff --git a/prebuilts/gradle/StorageProvider/Application/build.gradle b/prebuilts/gradle/StorageProvider/Application/build.gradle index bfed04fa..c6b8c26a 100644 --- a/prebuilts/gradle/StorageProvider/Application/build.gradle +++ b/prebuilts/gradle/StorageProvider/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:support-v13:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:support-v13:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/SwipeRefreshLayoutBasic/Application/build.gradle b/prebuilts/gradle/SwipeRefreshLayoutBasic/Application/build.gradle index 544e46b8..18c0d15c 100644 --- a/prebuilts/gradle/SwipeRefreshLayoutBasic/Application/build.gradle +++ b/prebuilts/gradle/SwipeRefreshLayoutBasic/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/SwipeRefreshListFragment/Application/build.gradle b/prebuilts/gradle/SwipeRefreshListFragment/Application/build.gradle index 544e46b8..18c0d15c 100644 --- a/prebuilts/gradle/SwipeRefreshListFragment/Application/build.gradle +++ b/prebuilts/gradle/SwipeRefreshListFragment/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/SwipeRefreshMultipleViews/Application/build.gradle b/prebuilts/gradle/SwipeRefreshMultipleViews/Application/build.gradle index 544e46b8..18c0d15c 100644 --- a/prebuilts/gradle/SwipeRefreshMultipleViews/Application/build.gradle +++ b/prebuilts/gradle/SwipeRefreshMultipleViews/Application/build.gradle @@ -17,9 +17,9 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" - compile "com.android.support:gridlayout-v7:21.+" - compile "com.android.support:cardview-v7:21.+" + compile "com.android.support:support-v4:21.0.2" + compile "com.android.support:gridlayout-v7:21.0.2" + compile "com.android.support:cardview-v7:21.0.2" } diff --git a/prebuilts/gradle/SynchronizedNotifications/.google/packaging.yaml b/prebuilts/gradle/SynchronizedNotifications/.google/packaging.yaml index bfa7a3c6..a930c527 100644 --- a/prebuilts/gradle/SynchronizedNotifications/.google/packaging.yaml +++ b/prebuilts/gradle/SynchronizedNotifications/.google/packaging.yaml @@ -9,4 +9,10 @@ categories: [Wearable] languages: [Java] solutions: [Mobile] github: android-SynchronizedNotifications +level: INTERMEDIATE +icon: screenshots/web-icon.png +apiRefs: + - android:com.google.android.gms.wearable.DataApi + - android:com.google.android.gms.wearable.Wearable + - android:com.google.android.gms.wearable.WearableListenerService license: apache2 diff --git a/prebuilts/gradle/SynchronizedNotifications/README.md b/prebuilts/gradle/SynchronizedNotifications/README.md index 98b20529..66cded4f 100644 --- a/prebuilts/gradle/SynchronizedNotifications/README.md +++ b/prebuilts/gradle/SynchronizedNotifications/README.md @@ -1,8 +1,51 @@ Android SynchronizedNotifications Sample =================================== -This sample creates simple or synchronized notifications on a -device and an Android Wear watch. +A basic sample showing how to use simple or synchronized notifications. +This allows users to dismiss events from either their phone or wearable device simultaneously. + +Introduction +------------ + +The [DataAPI][1] exposes an API for components to read or write data items and assets between +the handhelds and wearables. A [DataItem][2] is synchronized across all devices in an Android Wear network. +It is possible to set data items while not connected to any nodes. Those data items will be synchronized +when the nodes eventually come online. + +This example presents three buttons that would trigger three different combinations of +notifications on the handset and the watch: + +1. The first button builds a simple local-only notification on the handset. +2. The second one creates a wearable-only notification by putting a data item in the shared data +store and having a [com.google.android.gms.wearable.WearableListenerService][3] listen for +that on the wearable. +3. The third one creates a local notification and a wearable notification by combining the above +two. It, however, demonstrates how one can set things up so that the dismissal of one +notification results in the dismissal of the other one. + +In the #2 and #3 items, the following code is used to synchronize the data between the handheld +and the wearable devices using DataAPI. + +```java +PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(path); +putDataMapRequest.getDataMap().putString(Constants.KEY_CONTENT, content); +putDataMapRequest.getDataMap().putString(Constants.KEY_TITLE, title); +PutDataRequest request = putDataMapRequest.asPutDataRequest(); +Wearable.DataApi.putDataItem(mGoogleApiClient, request) + .setResultCallback(new ResultCallback<DataApi.DataItemResult>() { + @Override + public void onResult(DataApi.DataItemResult dataItemResult) { + if (!dataItemResult.getStatus().isSuccess()) { + Log.e(TAG, "buildWatchOnlyNotification(): Failed to set the data, " + + "status: " + dataItemResult.getStatus().getStatusCode()); + } + } + }); +``` + +[1]: http://developer.android.com/reference/com/google/android/gms/wearable/DataApi.html#putDataItem(com.google.android.gms.common.api.GoogleApiClient%2C%20com.google.android.gms.wearable.PutDataRequest) +[2]: http://developer.android.com/reference/com/google/android/gms/wearable/DataItem.html +[3]: https://developer.android.com/reference/com/google/android/gms/wearable/WearableListenerService.html Pre-requisites -------------- @@ -11,6 +54,11 @@ Pre-requisites - Android Build Tools v21.1.1 - Android Support Repository +Screenshots +------------- + +<img src="screenshots/different_notifications_phone.png" height="400" alt="Screenshot"/> <img src="screenshots/different_notifications_wearable.png" height="400" alt="Screenshot"/> <img src="screenshots/notification_options.png" height="400" alt="Screenshot"/> <img src="screenshots/watch_only_notification.png" height="400" alt="Screenshot"/> + Getting Started --------------- diff --git a/prebuilts/gradle/SynchronizedNotifications/screenshots/web-icon.png b/prebuilts/gradle/SynchronizedNotifications/screenshots/web-icon.png Binary files differnew file mode 100755 index 00000000..2f5f7093 --- /dev/null +++ b/prebuilts/gradle/SynchronizedNotifications/screenshots/web-icon.png diff --git a/prebuilts/gradle/TextLinkify/Application/build.gradle b/prebuilts/gradle/TextLinkify/Application/build.gradle index 05020be5..76169dee 100644 --- a/prebuilts/gradle/TextLinkify/Application/build.gradle +++ b/prebuilts/gradle/TextLinkify/Application/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" + compile "com.android.support:support-v4:21.0.2" } diff --git a/prebuilts/gradle/TextSwitcher/Application/build.gradle b/prebuilts/gradle/TextSwitcher/Application/build.gradle index 05020be5..76169dee 100644 --- a/prebuilts/gradle/TextSwitcher/Application/build.gradle +++ b/prebuilts/gradle/TextSwitcher/Application/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { - compile "com.android.support:support-v4:21.+" + compile "com.android.support:support-v4:21.0.2" } diff --git a/prebuilts/gradle/WatchFace/Wearable/src/main/AndroidManifest.xml b/prebuilts/gradle/WatchFace/Wearable/src/main/AndroidManifest.xml index ee906b76..5d4f208f 100644 --- a/prebuilts/gradle/WatchFace/Wearable/src/main/AndroidManifest.xml +++ b/prebuilts/gradle/WatchFace/Wearable/src/main/AndroidManifest.xml @@ -47,7 +47,7 @@ android:name="com.google.android.wearable.watchface.preview" android:resource="@drawable/preview_analog" /> <meta-data - android:name="com.google.android.clockwork.home.preview_circular" + android:name="com.google.android.wearable.watchface.preview_circular" android:resource="@drawable/preview_analog_circular" /> <meta-data android:name="com.google.android.wearable.watchface.companionConfigurationAction" @@ -71,7 +71,7 @@ android:name="com.google.android.wearable.watchface.preview" android:resource="@drawable/preview_analog" /> <meta-data - android:name="com.google.android.clockwork.home.preview_circular" + android:name="com.google.android.wearable.watchface.preview_circular" android:resource="@drawable/preview_analog_circular" /> <intent-filter> <action android:name="android.service.wallpaper.WallpaperService" /> @@ -92,7 +92,7 @@ android:name="com.google.android.wearable.watchface.preview" android:resource="@drawable/preview_tilt" /> <meta-data - android:name="com.google.android.clockwork.home.preview_circular" + android:name="com.google.android.wearable.watchface.preview_circular" android:resource="@drawable/preview_tilt_circular" /> <meta-data android:name="com.google.android.wearable.watchface.companionConfigurationAction" @@ -117,7 +117,7 @@ android:name="com.google.android.wearable.watchface.preview" android:resource="@drawable/preview_card_bounds" /> <meta-data - android:name="com.google.android.clockwork.home.preview_circular" + android:name="com.google.android.wearable.watchface.preview_circular" android:resource="@drawable/preview_card_bounds_circular" /> <meta-data android:name="com.google.android.wearable.watchface.companionConfigurationAction" @@ -141,7 +141,7 @@ android:name="com.google.android.wearable.watchface.preview" android:resource="@drawable/preview_digital" /> <meta-data - android:name="com.google.android.clockwork.home.preview_circular" + android:name="com.google.android.wearable.watchface.preview_circular" android:resource="@drawable/preview_digital_circular" /> <meta-data android:name="com.google.android.wearable.watchface.companionConfigurationAction" @@ -182,7 +182,7 @@ android:name="com.google.android.wearable.watchface.preview" android:resource="@drawable/preview_calendar" /> <meta-data - android:name="com.google.android.clockwork.home.preview_circular" + android:name="com.google.android.wearable.watchface.preview_circular" android:resource="@drawable/preview_calendar_circular" /> <intent-filter> <action android:name="android.service.wallpaper.WallpaperService" /> |