summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Pasanen <dan.pasanen@gmail.com>2017-04-05 07:23:29 -0500
committerDan Pasanen <dan.pasanen@gmail.com>2017-04-05 07:23:29 -0500
commit01b86c8784cd1590bfd7c467abc89880e9a12814 (patch)
treea04f8cc8c01c3499810b6eea0b38809ce7a7533e
parent132f0a9d42a59fcb96a34c8781da690fa97332d7 (diff)
parent99bfeb590ea8105d24ff0fdc6e41bed981483ee4 (diff)
downloadandroid_development-staging/cm-14.1_android-7.1.2_r2.tar.gz
android_development-staging/cm-14.1_android-7.1.2_r2.tar.bz2
android_development-staging/cm-14.1_android-7.1.2_r2.zip
Merge tag 'android-7.1.2_r2' into cm-14.1staging/cm-14.1_android-7.1.2_r2
Android 7.1.2 Release 2 (N2G47E) # gpg: Signature made Mon 03 Apr 2017 01:41:41 AM CDT # gpg: using DSA key E8AD3F819AB10E78 # gpg: Can't check signature: No public key
-rw-r--r--build/sdk.atree2
-rw-r--r--samples/NotePad/AndroidManifest.xml8
-rw-r--r--samples/NotePad/res/values/strings.xml1
-rw-r--r--samples/NotePad/src/com/example/android/notepad/NoteEditor.java297
-rw-r--r--samples/NotePad/src/com/example/android/notepad/NotePadProvider.java37
-rw-r--r--samples/NotePad/src/com/example/android/notepad/NotesList.java73
-rw-r--r--samples/NotePad/src/com/example/android/notepad/NotesLiveFolder.java113
-rw-r--r--samples/NotePad/src/com/example/android/notepad/TitleEditor.java134
-rw-r--r--samples/browseable/AccelerometerPlay/AndroidManifest.xml39
-rw-r--r--samples/browseable/AccelerometerPlay/_index.jd15
-rw-r--r--samples/browseable/AccelerometerPlay/res/drawable-hdpi/ball.pngbin13348 -> 0 bytes
-rw-r--r--samples/browseable/AccelerometerPlay/res/drawable-hdpi/wood.jpgbin195841 -> 0 bytes
-rw-r--r--samples/browseable/AccelerometerPlay/res/layout/main.xml23
-rw-r--r--samples/browseable/AccelerometerPlay/res/mipmap-hdpi/ic_launcher.pngbin3185 -> 0 bytes
-rw-r--r--samples/browseable/AccelerometerPlay/res/mipmap-mdpi/ic_launcher.pngbin1948 -> 0 bytes
-rw-r--r--samples/browseable/AccelerometerPlay/res/mipmap-xhdpi/ic_launcher.pngbin4103 -> 0 bytes
-rw-r--r--samples/browseable/AccelerometerPlay/res/mipmap-xxhdpi/ic_launcher.pngbin6538 -> 0 bytes
-rw-r--r--samples/browseable/AccelerometerPlay/res/mipmap-xxxhdpi/ic_launcher.pngbin9269 -> 0 bytes
-rw-r--r--samples/browseable/AccelerometerPlay/res/values/strings.xml19
-rw-r--r--samples/browseable/AccelerometerPlay/src/com.example.android.accelerometerplay/AccelerometerPlayActivity.java429
-rw-r--r--samples/browseable/ActionBarCompat-ShareActionProvider/_index.jd11
-rw-r--r--samples/browseable/ActiveNotifications/res/values/strings.xml4
-rw-r--r--samples/browseable/ActiveNotifications/src/com.example.android.activenotifications/ActiveNotificationsFragment.java39
-rw-r--r--samples/browseable/AdvancedImmersiveMode/res/layout/fragment_flags.xml30
-rw-r--r--samples/browseable/AdvancedImmersiveMode/res/values/strings.xml27
-rw-r--r--samples/browseable/AgendaData/Application/AndroidManifest.xml2
-rw-r--r--samples/browseable/AgendaData/Wearable/AndroidManifest.xml6
-rw-r--r--samples/browseable/AlwaysOn/AndroidManifest.xml7
-rw-r--r--samples/browseable/AppRestrictionEnforcer/AndroidManifest.xml6
-rw-r--r--samples/browseable/AppRestrictionEnforcer/_index.jd2
-rw-r--r--samples/browseable/AppRestrictionEnforcer/res/drawable-hdpi/ic_launcher.pngbin3667 -> 0 bytes
-rw-r--r--samples/browseable/AppRestrictionEnforcer/res/drawable-mdpi/ic_launcher.pngbin2299 -> 0 bytes
-rw-r--r--samples/browseable/AppRestrictionEnforcer/res/drawable-xhdpi/ic_launcher.pngbin5098 -> 0 bytes
-rw-r--r--samples/browseable/AppRestrictionEnforcer/res/drawable-xxhdpi/ic_launcher.pngbin9236 -> 0 bytes
-rw-r--r--samples/browseable/AppRestrictionEnforcer/res/layout/fragment_setup_profile.xml2
-rw-r--r--samples/browseable/AppRestrictionEnforcer/res/layout/separator.xml22
-rw-r--r--samples/browseable/AppRestrictionEnforcer/res/mipmap-hdpi/ic_launcher.pngbin0 -> 2880 bytes
-rw-r--r--samples/browseable/AppRestrictionEnforcer/res/mipmap-mdpi/ic_launcher.pngbin0 -> 1833 bytes
-rw-r--r--samples/browseable/AppRestrictionEnforcer/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 3700 bytes
-rw-r--r--samples/browseable/AppRestrictionEnforcer/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 5781 bytes
-rw-r--r--samples/browseable/AppRestrictionEnforcer/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 8479 bytes
-rw-r--r--samples/browseable/AppRestrictionEnforcer/res/values/base-strings.xml2
-rw-r--r--samples/browseable/AppRestrictionEnforcer/res/values/strings.xml2
-rw-r--r--samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/Constants.java3
-rw-r--r--samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/ItemAddFragment.java1
-rw-r--r--samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/MainActivity.java10
-rw-r--r--samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/SetupProfileFragment.java1
-rw-r--r--samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/StatusFragment.java10
-rw-r--r--samples/browseable/AppRestrictionSchema/AndroidManifest.xml8
-rw-r--r--samples/browseable/AppRestrictionSchema/res/drawable-hdpi/ic_launcher.pngbin3359 -> 0 bytes
-rw-r--r--samples/browseable/AppRestrictionSchema/res/drawable-mdpi/ic_launcher.pngbin2071 -> 0 bytes
-rw-r--r--samples/browseable/AppRestrictionSchema/res/drawable-xhdpi/ic_launcher.pngbin4618 -> 0 bytes
-rw-r--r--samples/browseable/AppRestrictionSchema/res/drawable-xxhdpi/ic_launcher.pngbin8491 -> 0 bytes
-rw-r--r--samples/browseable/AppRestrictionSchema/res/layout/fragment_app_restriction_schema.xml37
-rw-r--r--samples/browseable/AppRestrictionSchema/res/layout/separator.xml22
-rw-r--r--samples/browseable/AppRestrictionSchema/res/mipmap-hdpi/ic_launcher.pngbin0 -> 2846 bytes
-rw-r--r--samples/browseable/AppRestrictionSchema/res/mipmap-mdpi/ic_launcher.pngbin0 -> 1787 bytes
-rw-r--r--samples/browseable/AppRestrictionSchema/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 3607 bytes
-rw-r--r--samples/browseable/AppRestrictionSchema/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 5795 bytes
-rw-r--r--samples/browseable/AppRestrictionSchema/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 8470 bytes
-rw-r--r--samples/browseable/AppRestrictionSchema/src/com.example.android.apprestrictionschema/AppRestrictionSchemaFragment.java6
-rw-r--r--samples/browseable/AppRestrictions/AndroidManifest.xml5
-rwxr-xr-xsamples/browseable/AppRestrictions/res/drawable-hdpi/ic_launcher.pngbin4216 -> 0 bytes
-rwxr-xr-xsamples/browseable/AppRestrictions/res/drawable-mdpi/ic_launcher.pngbin2627 -> 0 bytes
-rwxr-xr-xsamples/browseable/AppRestrictions/res/drawable-xhdpi/ic_launcher.pngbin5833 -> 0 bytes
-rwxr-xr-xsamples/browseable/AppRestrictions/res/drawable-xxhdpi/ic_launcher.pngbin10458 -> 0 bytes
-rw-r--r--samples/browseable/AppRestrictions/res/layout/main.xml10
-rw-r--r--samples/browseable/AppRestrictions/res/mipmap-hdpi/ic_launcher.pngbin0 -> 3463 bytes
-rw-r--r--samples/browseable/AppRestrictions/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2217 bytes
-rw-r--r--samples/browseable/AppRestrictions/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4390 bytes
-rw-r--r--samples/browseable/AppRestrictions/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 7001 bytes
-rw-r--r--samples/browseable/AppRestrictions/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 9635 bytes
-rw-r--r--samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsFragment.java26
-rw-r--r--samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/GetRestrictionsReceiver.java2
-rw-r--r--samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/MainActivity.java4
-rw-r--r--samples/browseable/AppShortcuts/AndroidManifest.xml3
-rw-r--r--samples/browseable/AppShortcuts/res/drawable-nodpi/app.pngbin16072 -> 0 bytes
-rwxr-xr-xsamples/browseable/AppShortcuts/res/mipmap-hdpi/ic_launcher.pngbin0 -> 2833 bytes
-rw-r--r--samples/browseable/AppShortcuts/res/mipmap-hdpi/ic_launcher_round.pngbin0 -> 5236 bytes
-rwxr-xr-xsamples/browseable/AppShortcuts/res/mipmap-mdpi/ic_launcher.pngbin0 -> 1868 bytes
-rw-r--r--samples/browseable/AppShortcuts/res/mipmap-mdpi/ic_launcher_round.pngbin0 -> 3642 bytes
-rwxr-xr-xsamples/browseable/AppShortcuts/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 3707 bytes
-rw-r--r--samples/browseable/AppShortcuts/res/mipmap-xhdpi/ic_launcher_round.pngbin0 -> 6726 bytes
-rwxr-xr-xsamples/browseable/AppShortcuts/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 5966 bytes
-rw-r--r--samples/browseable/AppShortcuts/res/mipmap-xxhdpi/ic_launcher_round.pngbin0 -> 10479 bytes
-rwxr-xr-xsamples/browseable/AppShortcuts/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 8610 bytes
-rw-r--r--samples/browseable/AppShortcuts/res/mipmap-xxxhdpi/ic_launcher_round.pngbin0 -> 13724 bytes
-rw-r--r--samples/browseable/AsymmetricFingerprintDialog/AndroidManifest.xml32
-rw-r--r--samples/browseable/AsymmetricFingerprintDialog/res/layout/activity_main.xml6
-rw-r--r--samples/browseable/AsymmetricFingerprintDialog/res/layout/fingerprint_dialog_content.xml3
-rw-r--r--samples/browseable/AsymmetricFingerprintDialog/res/menu/menu_main.xml11
-rw-r--r--samples/browseable/AsymmetricFingerprintDialog/res/values/strings.xml4
-rw-r--r--samples/browseable/AsymmetricFingerprintDialog/src/com.example.android.asymmetricfingerprintdialog/FingerprintAuthenticationDialogFragment.java8
-rw-r--r--samples/browseable/AsymmetricFingerprintDialog/src/com.example.android.asymmetricfingerprintdialog/FingerprintUiHelper.java4
-rw-r--r--samples/browseable/BasicAndroidKeyStore/AndroidManifest.xml2
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/ic_launcher.pngbin4199 -> 0 bytes
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/drawable-mdpi/ic_launcher.pngbin2535 -> 0 bytes
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/drawable-xhdpi/ic_launcher.pngbin6022 -> 0 bytes
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/drawable-xxhdpi/ic_launcher.pngbin11040 -> 0 bytes
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/mipmap-hdpi/ic_launcher.pngbin0 -> 3217 bytes
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2006 bytes
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4021 bytes
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 6521 bytes
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 9058 bytes
-rw-r--r--samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/BasicAndroidKeyStoreFragment.java70
-rw-r--r--samples/browseable/BasicGestureDetect/res/menu/main.xml5
-rw-r--r--samples/browseable/BasicImmersiveMode/res/menu/main.xml5
-rw-r--r--samples/browseable/BluetoothChat/src/com.example.android.bluetoothchat/BluetoothChatFragment.java4
-rw-r--r--samples/browseable/BluetoothChat/src/com.example.android.bluetoothchat/BluetoothChatService.java43
-rw-r--r--samples/browseable/CardView/_index.jd4
-rw-r--r--samples/browseable/CardView/res/values/base-strings.xml4
-rw-r--r--samples/browseable/CommitContentSampleApp/AndroidManifest.xml1
-rwxr-xr-x[-rw-r--r--]samples/browseable/CommitContentSampleApp/res/mipmap-hdpi/ic_launcher.pngbin3418 -> 3358 bytes
-rw-r--r--samples/browseable/CommitContentSampleApp/res/mipmap-hdpi/ic_launcher_round.pngbin0 -> 5801 bytes
-rwxr-xr-x[-rw-r--r--]samples/browseable/CommitContentSampleApp/res/mipmap-mdpi/ic_launcher.pngbin2206 -> 2222 bytes
-rw-r--r--samples/browseable/CommitContentSampleApp/res/mipmap-mdpi/ic_launcher_round.pngbin0 -> 4159 bytes
-rwxr-xr-x[-rw-r--r--]samples/browseable/CommitContentSampleApp/res/mipmap-xhdpi/ic_launcher.pngbin4842 -> 4327 bytes
-rw-r--r--samples/browseable/CommitContentSampleApp/res/mipmap-xhdpi/ic_launcher_round.pngbin0 -> 7508 bytes
-rwxr-xr-x[-rw-r--r--]samples/browseable/CommitContentSampleApp/res/mipmap-xxhdpi/ic_launcher.pngbin7718 -> 6647 bytes
-rw-r--r--samples/browseable/CommitContentSampleApp/res/mipmap-xxhdpi/ic_launcher_round.pngbin0 -> 11056 bytes
-rwxr-xr-x[-rw-r--r--]samples/browseable/CommitContentSampleApp/res/mipmap-xxxhdpi/ic_launcher.pngbin10486 -> 9285 bytes
-rw-r--r--samples/browseable/CommitContentSampleApp/res/mipmap-xxxhdpi/ic_launcher_round.pngbin0 -> 14100 bytes
-rw-r--r--samples/browseable/CommitContentSampleIME/AndroidManifest.xml1
-rwxr-xr-x[-rw-r--r--]samples/browseable/CommitContentSampleIME/res/mipmap-hdpi/ic_launcher.pngbin3418 -> 3358 bytes
-rw-r--r--samples/browseable/CommitContentSampleIME/res/mipmap-hdpi/ic_launcher_round.pngbin0 -> 5801 bytes
-rwxr-xr-x[-rw-r--r--]samples/browseable/CommitContentSampleIME/res/mipmap-mdpi/ic_launcher.pngbin2206 -> 2222 bytes
-rw-r--r--samples/browseable/CommitContentSampleIME/res/mipmap-mdpi/ic_launcher_round.pngbin0 -> 4159 bytes
-rwxr-xr-x[-rw-r--r--]samples/browseable/CommitContentSampleIME/res/mipmap-xhdpi/ic_launcher.pngbin4842 -> 4327 bytes
-rw-r--r--samples/browseable/CommitContentSampleIME/res/mipmap-xhdpi/ic_launcher_round.pngbin0 -> 7508 bytes
-rwxr-xr-x[-rw-r--r--]samples/browseable/CommitContentSampleIME/res/mipmap-xxhdpi/ic_launcher.pngbin7718 -> 6647 bytes
-rw-r--r--samples/browseable/CommitContentSampleIME/res/mipmap-xxhdpi/ic_launcher_round.pngbin0 -> 11056 bytes
-rwxr-xr-x[-rw-r--r--]samples/browseable/CommitContentSampleIME/res/mipmap-xxxhdpi/ic_launcher.pngbin10486 -> 9285 bytes
-rw-r--r--samples/browseable/CommitContentSampleIME/res/mipmap-xxxhdpi/ic_launcher_round.pngbin0 -> 14100 bytes
-rw-r--r--samples/browseable/CommitContentSampleIME/src/com.example.android.commitcontent.ime/ImageKeyboard.java2
-rw-r--r--samples/browseable/DataLayer/Wearable/AndroidManifest.xml6
-rw-r--r--samples/browseable/DirectBoot/src/com.example.android.directboot/SchedulerFragment.java2
-rw-r--r--samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/Alarm.java52
-rw-r--r--samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/AlarmIntentService.java16
-rw-r--r--samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/AlarmUtil.java27
-rw-r--r--samples/browseable/ElevationBasic/res/layout/elevation_basic.xml5
-rw-r--r--samples/browseable/ElevationBasic/src/com.example.android.elevationbasic/ElevationBasicFragment.java1
-rw-r--r--samples/browseable/FingerprintDialog/AndroidManifest.xml33
-rw-r--r--samples/browseable/FingerprintDialog/res/layout/activity_main.xml3
-rw-r--r--samples/browseable/FingerprintDialog/res/layout/fingerprint_dialog_content.xml3
-rw-r--r--samples/browseable/FingerprintDialog/res/menu/menu_main.xml14
-rw-r--r--samples/browseable/FingerprintDialog/res/values/strings.xml4
-rw-r--r--samples/browseable/FingerprintDialog/src/com.example.android.fingerprintdialog/FingerprintAuthenticationDialogFragment.java12
-rw-r--r--samples/browseable/GridViewPager/AndroidManifest.xml5
-rw-r--r--samples/browseable/ImmersiveMode/res/menu/main.xml5
-rw-r--r--samples/browseable/JobScheduler/AndroidManifest.xml2
-rw-r--r--samples/browseable/JobScheduler/res/layout/sample_main.xml215
-rw-r--r--samples/browseable/JobScheduler/res/values/strings.xml7
-rw-r--r--samples/browseable/JobScheduler/src/com.example.android.jobscheduler/MainActivity.java271
-rw-r--r--samples/browseable/JobScheduler/src/com.example.android.jobscheduler/service/MyJobService.java119
-rw-r--r--samples/browseable/JobScheduler/src/com.example.android.jobscheduler/service/TestJobService.java127
-rw-r--r--samples/browseable/JumpingJack/AndroidManifest.xml7
-rw-r--r--samples/browseable/LNotifications/res/layout/activity_notification.xml24
-rw-r--r--samples/browseable/LNotifications/src/com.example.android.lnotifications/HeadsUpNotificationFragment.java5
-rw-r--r--samples/browseable/LNotifications/src/com.example.android.lnotifications/LNotificationActivity.java81
-rw-r--r--samples/browseable/LNotifications/src/com.example.android.lnotifications/OtherMetadataFragment.java21
-rw-r--r--samples/browseable/LNotifications/src/com.example.android.lnotifications/VisibilityMetadataFragment.java16
-rw-r--r--samples/browseable/NetworkConnect/AndroidManifest.xml4
-rw-r--r--samples/browseable/NetworkConnect/_index.jd2
-rwxr-xr-xsamples/browseable/NetworkConnect/res/layout/sample_main.xml18
-rw-r--r--samples/browseable/NetworkConnect/res/values/base-strings.xml2
-rwxr-xr-xsamples/browseable/NetworkConnect/res/values/strings.xml2
-rw-r--r--samples/browseable/NetworkConnect/res/xml/network_security_config.xml7
-rw-r--r--samples/browseable/NetworkConnect/src/com.example.android.common.logger/Log.java236
-rw-r--r--samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogFragment.java109
-rw-r--r--samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogNode.java39
-rw-r--r--samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogView.java145
-rw-r--r--samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogWrapper.java75
-rw-r--r--samples/browseable/NetworkConnect/src/com.example.android.common.logger/MessageOnlyLogFilter.java60
-rw-r--r--samples/browseable/NetworkConnect/src/com.example.android.networkconnect/DownloadCallback.java60
-rwxr-xr-xsamples/browseable/NetworkConnect/src/com.example.android.networkconnect/MainActivity.java191
-rw-r--r--samples/browseable/NetworkConnect/src/com.example.android.networkconnect/NetworkFragment.java289
-rw-r--r--samples/browseable/NetworkConnect/src/com.example.android.networkconnect/SimpleTextFragment.java98
-rw-r--r--samples/browseable/Notifications/Application/AndroidManifest.xml2
-rw-r--r--samples/browseable/Notifications/Application/res/values/base-strings.xml2
-rw-r--r--samples/browseable/Notifications/Wearable/AndroidManifest.xml8
-rw-r--r--samples/browseable/Notifications/_index.jd2
-rw-r--r--samples/browseable/PdfRendererBasic/src/com.example.android.pdfrendererbasic/PdfRendererBasicFragment.java24
-rw-r--r--samples/browseable/PermissionRequest/res/values/strings.xml1
-rw-r--r--samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/ConfirmationDialogFragment.java20
-rw-r--r--samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/MessageDialogFragment.java61
-rw-r--r--samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/PermissionRequestFragment.java67
-rw-r--r--samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/SimpleWebServer.java4
-rw-r--r--samples/browseable/RepeatingAlarm/res/menu/main.xml5
-rw-r--r--samples/browseable/RuntimePermissionsWear/Wearable/AndroidManifest.xml4
-rw-r--r--samples/browseable/ShareActionProvider/AndroidManifest.xml (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/AndroidManifest.xml)16
-rw-r--r--samples/browseable/ShareActionProvider/_index.jd10
-rw-r--r--samples/browseable/ShareActionProvider/res/drawable-hdpi/ic_launcher.png (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-hdpi/ic_launcher.png)bin4289 -> 4289 bytes
-rw-r--r--samples/browseable/ShareActionProvider/res/drawable-hdpi/tile.9.png (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-hdpi/tile.9.png)bin196 -> 196 bytes
-rw-r--r--samples/browseable/ShareActionProvider/res/drawable-mdpi/ic_launcher.png (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-mdpi/ic_launcher.png)bin2583 -> 2583 bytes
-rw-r--r--samples/browseable/ShareActionProvider/res/drawable-xhdpi/ic_launcher.png (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-xhdpi/ic_launcher.png)bin6170 -> 6170 bytes
-rw-r--r--samples/browseable/ShareActionProvider/res/drawable-xxhdpi/ic_launcher.png (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-xxhdpi/ic_launcher.png)bin11093 -> 11093 bytes
-rw-r--r--samples/browseable/ShareActionProvider/res/layout/item_image.xml (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/item_image.xml)0
-rw-r--r--samples/browseable/ShareActionProvider/res/layout/item_text.xml (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/item_text.xml)0
-rw-r--r--samples/browseable/ShareActionProvider/res/layout/sample_main.xml (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/sample_main.xml)0
-rw-r--r--samples/browseable/ShareActionProvider/res/menu/main_menu.xml (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/menu/main_menu.xml)7
-rw-r--r--samples/browseable/ShareActionProvider/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/values-sw600dp/template-dimens.xml)0
-rw-r--r--samples/browseable/ShareActionProvider/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/values-sw600dp/template-styles.xml)0
-rw-r--r--samples/browseable/ShareActionProvider/res/values-v11/template-styles.xml (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/values-v11/template-styles.xml)0
-rw-r--r--samples/browseable/ShareActionProvider/res/values-v21/base-colors.xml (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/values-v21/base-colors.xml)0
-rw-r--r--samples/browseable/ShareActionProvider/res/values-v21/base-template-styles.xml (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/values-v21/base-template-styles.xml)0
-rw-r--r--samples/browseable/ShareActionProvider/res/values/base-strings.xml (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/values/base-strings.xml)5
-rw-r--r--samples/browseable/ShareActionProvider/res/values/strings.xml (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/values/strings.xml)0
-rw-r--r--samples/browseable/ShareActionProvider/res/values/template-dimens.xml (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/values/template-dimens.xml)0
-rw-r--r--samples/browseable/ShareActionProvider/res/values/template-styles.xml (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/res/values/template-styles.xml)0
-rw-r--r--samples/browseable/ShareActionProvider/src/com.example.android.shareactionprovider/MainActivity.java (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/MainActivity.java)14
-rw-r--r--samples/browseable/ShareActionProvider/src/com.example.android.shareactionprovider/content/AssetProvider.java (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/AssetProvider.java)25
-rw-r--r--samples/browseable/ShareActionProvider/src/com.example.android.shareactionprovider/content/ContentItem.java (renamed from samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/ContentItem.java)12
-rw-r--r--samples/browseable/SpeedTracker/Application/AndroidManifest.xml2
-rw-r--r--samples/browseable/SpeedTracker/Application/res/layout/main_activity.xml8
-rw-r--r--samples/browseable/SpeedTracker/Application/res/values/base-strings.xml5
-rw-r--r--samples/browseable/SpeedTracker/Application/src/com.example.android.wearable.speedtracker/PhoneMainActivity.java14
-rw-r--r--samples/browseable/SpeedTracker/Wearable/AndroidManifest.xml6
-rw-r--r--samples/browseable/SpeedTracker/Wearable/src/com.example.android.wearable.speedtracker/WearableMainActivity.java2
-rw-r--r--samples/browseable/SpeedTracker/_index.jd5
-rw-r--r--samples/browseable/StorageClient/res/menu/main.xml5
-rw-r--r--samples/browseable/StorageProvider/res/menu/main.xml5
-rw-r--r--samples/browseable/SwipeRefreshMultipleViews/src/com.example.android.swiperefreshmultipleviews/SwipeRefreshMultipleViewsFragment.java11
-rw-r--r--samples/browseable/SynchronizedNotifications/Wearable/AndroidManifest.xml7
-rw-r--r--samples/browseable/WatchFace/Application/AndroidManifest.xml2
-rw-r--r--samples/browseable/WatchFace/Application/res/values/base-strings.xml27
-rw-r--r--samples/browseable/WatchFace/Wearable/AndroidManifest.xml13
-rw-r--r--samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/DigitalWatchFaceService.java10
-rw-r--r--samples/browseable/WatchFace/_index.jd27
-rw-r--r--samples/browseable/WatchViewStub/AndroidManifest.xml9
-rw-r--r--samples/browseable/WearDrawers/AndroidManifest.xml4
-rw-r--r--samples/browseable/WearDrawers/src/com.example.android.wearable.wear.weardrawers/MainActivity.java18
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/AndroidManifest.xml50
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/_index.jd13
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/drawable/bg_action_button.xml4
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_cloud_disconnected.xml12
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_cloud_happy.xml20
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_cloud_sad.xml20
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_fast_network.xml11
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_no_network.xml11
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_wifi_network.xml11
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/layout/activity_main.xml101
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/mipmap-hdpi/ic_launcher.pngbin0 -> 3418 bytes
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2206 bytes
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4842 bytes
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 7718 bytes
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/values/colors.xml43
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/values/dimens.xml22
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/values/strings.xml32
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/values/styles.xml59
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/res/values/themes.xml24
-rw-r--r--samples/browseable/WearHighBandwidthNetworking/src/com.example.android.wearable.wear.wearhighbandwidthnetworking/MainActivity.java340
-rw-r--r--samples/browseable/WearNotifications/Application/res/values/base-strings.xml2
-rw-r--r--samples/browseable/WearNotifications/Wearable/AndroidManifest.xml35
-rw-r--r--samples/browseable/WearNotifications/Wearable/res/drawable-hdpi/ic_n_white_48dp.pngbin0 -> 2086 bytes
-rw-r--r--samples/browseable/WearNotifications/Wearable/res/layout/activity_big_picture_main.xml36
-rw-r--r--samples/browseable/WearNotifications/Wearable/res/layout/activity_big_text_main.xml36
-rw-r--r--samples/browseable/WearNotifications/Wearable/res/layout/activity_inbox_main.xml36
-rw-r--r--samples/browseable/WearNotifications/Wearable/res/layout/activity_main.xml69
-rw-r--r--samples/browseable/WearNotifications/Wearable/res/layout/activity_messaging_main.xml36
-rw-r--r--samples/browseable/WearNotifications/Wearable/res/layout/recycler_row_item.xml37
-rw-r--r--samples/browseable/WearNotifications/Wearable/res/values-round/dimens.xml38
-rw-r--r--samples/browseable/WearNotifications/Wearable/res/values-round/strings.xml19
-rw-r--r--samples/browseable/WearNotifications/Wearable/res/values/colors.xml28
-rw-r--r--samples/browseable/WearNotifications/Wearable/res/values/dimens.xml41
-rw-r--r--samples/browseable/WearNotifications/Wearable/res/values/strings.xml30
-rw-r--r--samples/browseable/WearNotifications/Wearable/res/values/styles.xml19
-rw-r--r--samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/Controller.java22
-rw-r--r--samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/CustomRecyclerAdapter.java95
-rw-r--r--samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/GlobalNotificationBuilder.java26
-rw-r--r--samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/ScalingOffsettingHelper.java53
-rw-r--r--samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/StandaloneMainActivity.java117
-rw-r--r--samples/browseable/WearNotifications/_index.jd2
-rw-r--r--samples/browseable/WearSpeakerSample/AndroidManifest.xml8
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/AndroidManifest.xml35
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/drawable-hdpi/tile.9.pngbin0 -> 196 bytes
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/layout/activity_main.xml42
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-hdpi/ic_launcher.pngbin0 -> 3418 bytes
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2206 bytes
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4842 bytes
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 7718 bytes
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 10486 bytes
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/values-sw600dp/template-dimens.xml24
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/values-sw600dp/template-styles.xml25
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/values-v11/template-styles.xml22
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/values-v21/base-colors.xml21
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/values-v21/base-template-styles.xml24
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/values/base-strings.xml31
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/values/colors.xml21
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/values/dimens.xml21
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/values/styles.xml27
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/values/template-styles.xml42
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/res/values/wear.xml22
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Application/src/com.example.android.wearable.wear.wearverifyremoteapp/MainMobileActivity.java341
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Wearable/AndroidManifest.xml51
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Wearable/res/layout/activity_main.xml42
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-hdpi/ic_launcher.pngbin0 -> 3418 bytes
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2206 bytes
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4842 bytes
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 7718 bytes
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Wearable/res/values-round/dimens.xml22
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Wearable/res/values/dimens.xml22
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Wearable/res/values/strings.xml19
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Wearable/res/values/wear.xml22
-rw-r--r--samples/browseable/WearVerifyRemoteApp/Wearable/src/com.example.android.wearable.wear.wearverifyremoteapp/MainWearActivity.java302
-rw-r--r--samples/browseable/WearVerifyRemoteApp/_index.jd12
-rw-r--r--samples/browseable/XYZTouristAttractions/Wearable/AndroidManifest.xml8
-rw-r--r--samples/samples_source.prop_template2
-rw-r--r--testrunner/test_defs.xml1
309 files changed, 4485 insertions, 2904 deletions
diff --git a/build/sdk.atree b/build/sdk.atree
index 093bd3a38..c1e86e213 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -286,7 +286,7 @@ developers/build/prebuilts/gradle/TextSwitcher/ sam
developers/build/prebuilts/gradle/HorizontalPaging/ samples/${PLATFORM_NAME}/ui/HorizontalPaging
developers/build/prebuilts/gradle/ActionBarCompat-Styled/ samples/${PLATFORM_NAME}/ui/ActionBarCompat-Styled
developers/build/prebuilts/gradle/ActionBarCompat-ListPopupMenu/ samples/${PLATFORM_NAME}/ui/ActionBarCompat-ListPopupMenu
-developers/build/prebuilts/gradle/ActionBarCompat-ShareActionProvider/ samples/${PLATFORM_NAME}/ui/ActionBarCompat-ShareActionProvider
+developers/build/prebuilts/gradle/ShareActionProvider/ samples/${PLATFORM_NAME}/ui/ShareActionProvider
developers/build/prebuilts/gradle/ActionBarCompat-Basic/ samples/${PLATFORM_NAME}/ui/ActionBarCompat-Basic
developers/build/prebuilts/gradle/BasicNotifications/ samples/${PLATFORM_NAME}/ui/BasicNotifications
developers/build/prebuilts/gradle/CustomNotifications/ samples/${PLATFORM_NAME}/ui/CustomNotifications
diff --git a/samples/NotePad/AndroidManifest.xml b/samples/NotePad/AndroidManifest.xml
index ead782925..51e848d8e 100644
--- a/samples/NotePad/AndroidManifest.xml
+++ b/samples/NotePad/AndroidManifest.xml
@@ -107,14 +107,6 @@
</intent-filter>
</activity>
- <activity android:name="NotesLiveFolder" android:label="@string/live_folder_name"
- android:icon="@drawable/live_folder_notes">
- <intent-filter>
- <action android:name="android.intent.action.CREATE_LIVE_FOLDER" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
-
</application>
</manifest>
diff --git a/samples/NotePad/res/values/strings.xml b/samples/NotePad/res/values/strings.xml
index 26d23d072..508fa439f 100644
--- a/samples/NotePad/res/values/strings.xml
+++ b/samples/NotePad/res/values/strings.xml
@@ -40,4 +40,5 @@
<string name="error_title">Error</string>
<string name="error_message">Error loading note</string>
<string name="nothing_to_save">There is nothing to save</string>
+ <string name="title_blank">Blank title not saved</string>
</resources> \ No newline at end of file
diff --git a/samples/NotePad/src/com/example/android/notepad/NoteEditor.java b/samples/NotePad/src/com/example/android/notepad/NoteEditor.java
index 59d6f1290..b8b070f20 100644
--- a/samples/NotePad/src/com/example/android/notepad/NoteEditor.java
+++ b/samples/NotePad/src/com/example/android/notepad/NoteEditor.java
@@ -17,13 +17,16 @@
package com.example.android.notepad;
import android.app.Activity;
+import android.app.LoaderManager;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.content.CursorLoader;
import android.content.Intent;
+import android.content.Loader;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Canvas;
@@ -37,19 +40,15 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.EditText;
+import com.example.android.notepad.NotePad.Notes;
/**
* This Activity handles "editing" a note, where editing is responding to
* {@link Intent#ACTION_VIEW} (request to view data), edit a note
* {@link Intent#ACTION_EDIT}, create a note {@link Intent#ACTION_INSERT}, or
* create a new note from the current contents of the clipboard {@link Intent#ACTION_PASTE}.
- *
- * NOTE: Notice that the provider operations in this Activity are taking place on the UI thread.
- * This is not a good practice. It is only done here to make the code more readable. A real
- * application should use the {@link android.content.AsyncQueryHandler}
- * or {@link android.os.AsyncTask} object to perform operations asynchronously on a separate thread.
*/
-public class NoteEditor extends Activity {
+public class NoteEditor extends Activity implements LoaderManager.LoaderCallbacks<Cursor> {
// For logging and debugging purposes
private static final String TAG = "NoteEditor";
@@ -71,10 +70,11 @@ public class NoteEditor extends Activity {
private static final int STATE_EDIT = 0;
private static final int STATE_INSERT = 1;
+ private static final int LOADER_ID = 1;
+
// Global mutable variables
private int mState;
private Uri mUri;
- private Cursor mCursor;
private EditText mText;
private String mOriginalContent;
@@ -139,6 +139,11 @@ public class NoteEditor extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ // Recovering the instance state from a previously destroyed Activity instance
+ if (savedInstanceState != null) {
+ mOriginalContent = savedInstanceState.getString(ORIGINAL_CONTENT);
+ }
+
/*
* Creates an Intent to use when the Activity object's result is sent back to the
* caller.
@@ -166,6 +171,8 @@ public class NoteEditor extends Activity {
// Sets the Activity state to INSERT, gets the general note URI, and inserts an
// empty record in the provider
mState = STATE_INSERT;
+ setTitle(getText(R.string.title_create));
+
mUri = getContentResolver().insert(intent.getData(), null);
/*
@@ -197,24 +204,10 @@ public class NoteEditor extends Activity {
return;
}
- /*
- * Using the URI passed in with the triggering Intent, gets the note or notes in
- * the provider.
- * Note: This is being done on the UI thread. It will block the thread until the query
- * completes. In a sample app, going against a simple provider based on a local database,
- * the block will be momentary, but in a real app you should use
- * android.content.AsyncQueryHandler or android.os.AsyncTask.
- */
- mCursor = managedQuery(
- mUri, // The URI that gets multiple notes from the provider.
- PROJECTION, // A projection that returns the note ID and note content for each note.
- null, // No "where" clause selection criteria.
- null, // No "where" clause selection values.
- null // Use the default sort order (modification date, descending)
- );
+ // Initialize the LoaderManager and start the query
+ getLoaderManager().initLoader(LOADER_ID, null, this);
// For a paste, initializes the data from clipboard.
- // (Must be done after mCursor is initialized.)
if (Intent.ACTION_PASTE.equals(action)) {
// Does the paste
performPaste();
@@ -227,87 +220,12 @@ public class NoteEditor extends Activity {
// Gets a handle to the EditText in the the layout.
mText = (EditText) findViewById(R.id.note);
-
- /*
- * If this Activity had stopped previously, its state was written the ORIGINAL_CONTENT
- * location in the saved Instance state. This gets the state.
- */
- if (savedInstanceState != null) {
- mOriginalContent = savedInstanceState.getString(ORIGINAL_CONTENT);
- }
}
- /**
- * This method is called when the Activity is about to come to the foreground. This happens
- * when the Activity comes to the top of the task stack, OR when it is first starting.
- *
- * Moves to the first note in the list, sets an appropriate title for the action chosen by
- * the user, puts the note contents into the TextView, and saves the original text as a
- * backup.
- */
- @Override
- protected void onResume() {
- super.onResume();
-
- /*
- * mCursor is initialized, since onCreate() always precedes onResume for any running
- * process. This tests that it's not null, since it should always contain data.
- */
- if (mCursor != null) {
- // Requery in case something changed while paused (such as the title)
- mCursor.requery();
-
- /* Moves to the first record. Always call moveToFirst() before accessing data in
- * a Cursor for the first time. The semantics of using a Cursor are that when it is
- * created, its internal index is pointing to a "place" immediately before the first
- * record.
- */
- mCursor.moveToFirst();
-
- // Modifies the window title for the Activity according to the current Activity state.
- if (mState == STATE_EDIT) {
- // Set the title of the Activity to include the note title
- int colTitleIndex = mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_TITLE);
- String title = mCursor.getString(colTitleIndex);
- Resources res = getResources();
- String text = String.format(res.getString(R.string.title_edit), title);
- setTitle(text);
- // Sets the title to "create" for inserts
- } else if (mState == STATE_INSERT) {
- setTitle(getText(R.string.title_create));
- }
-
- /*
- * onResume() may have been called after the Activity lost focus (was paused).
- * The user was either editing or creating a note when the Activity paused.
- * The Activity should re-display the text that had been retrieved previously, but
- * it should not move the cursor. This helps the user to continue editing or entering.
- */
-
- // Gets the note text from the Cursor and puts it in the TextView, but doesn't change
- // the text cursor's position.
- int colNoteIndex = mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_NOTE);
- String note = mCursor.getString(colNoteIndex);
- mText.setTextKeepState(note);
-
- // Stores the original note text, to allow the user to revert changes.
- if (mOriginalContent == null) {
- mOriginalContent = note;
- }
-
- /*
- * Something is wrong. The Cursor should always contain data. Report an error in the
- * note.
- */
- } else {
- setTitle(getText(R.string.error_title));
- mText.setText(getText(R.string.error_message));
- }
- }
/**
- * This method is called when an Activity loses focus during its normal operation, and is then
- * later on killed. The Activity has a chance to save its state so that the system can restore
+ * This method is called when an Activity loses focus during its normal operation.
+ * The Activity has a chance to save its state so that the system can restore
* it.
*
* Notice that this method isn't a normal part of the Activity lifecycle. It won't be called
@@ -316,37 +234,52 @@ public class NoteEditor extends Activity {
@Override
protected void onSaveInstanceState(Bundle outState) {
// Save away the original text, so we still have it if the activity
- // needs to be killed while paused.
+ // needs to be re-created.
outState.putString(ORIGINAL_CONTENT, mOriginalContent);
+ // Call the superclass to save the any view hierarchy state
+ super.onSaveInstanceState(outState);
}
/**
* This method is called when the Activity loses focus.
*
- * For Activity objects that edit information, onPause() may be the one place where changes are
- * saved. The Android application model is predicated on the idea that "save" and "exit" aren't
- * required actions. When users navigate away from an Activity, they shouldn't have to go back
- * to it to complete their work. The act of going away should save everything and leave the
- * Activity in a state where Android can destroy it if necessary.
- *
- * If the user hasn't done anything, then this deletes or clears out the note, otherwise it
- * writes the user's work to the provider.
+ * While there is no need to override this method in this app, it is shown here to highlight
+ * that we are not saving any state in onPause, but have moved app state saving to onStop
+ * callback.
+ * In earlier versions of this app and popular literature it had been shown that onPause is good
+ * place to persist any unsaved work, however, this is not really a good practice because of how
+ * application and process lifecycle behave.
+ * As a general guideline apps should have a way of saving their business logic that does not
+ * solely rely on Activity (or other component) lifecyle state transitions.
+ * As a backstop you should save any app state, not saved during lifetime of the Activity, in
+ * onStop().
+ * For a more detailed explanation of this recommendation please read
+ * <a href = "https://developer.android.com/guide/topics/processes/process-lifecycle.html">
+ * Processes and Application Life Cycle </a>.
+ * <a href="https://developer.android.com/training/basics/activity-lifecycle/pausing.html">
+ * Pausing and Resuming an Activity </a>.
*/
@Override
protected void onPause() {
super.onPause();
+ }
- /*
- * Tests to see that the query operation didn't fail (see onCreate()). The Cursor object
- * will exist, even if no records were returned, unless the query failed because of some
- * exception or error.
- *
- */
- if (mCursor != null) {
+ /**
+ * This method is called when the Activity becomes invisible.
+ *
+ * For Activity objects that edit information, onStop() may be the one place where changes maybe
+ * saved.
+ *
+ * If the user hasn't done anything, then this deletes or clears out the note, otherwise it
+ * writes the user's work to the provider.
+ */
+ @Override
+ protected void onStop() {
+ super.onStop();
- // Get the current note text.
- String text = mText.getText().toString();
- int length = text.length();
+ // Get the current note text.
+ String text = mText.getText().toString();
+ int length = text.length();
/*
* If the Activity is in the midst of finishing and there is no text in the current
@@ -354,23 +287,22 @@ public class NoteEditor extends Activity {
* even if the note was being edited, the assumption being that the user wanted to
* "clear out" (delete) the note.
*/
- if (isFinishing() && (length == 0)) {
- setResult(RESULT_CANCELED);
- deleteNote();
+ if (isFinishing() && (length == 0)) {
+ setResult(RESULT_CANCELED);
+ deleteNote();
/*
- * Writes the edits to the provider. The note has been edited if an existing note was
- * retrieved into the editor *or* if a new note was inserted. In the latter case,
- * onCreate() inserted a new empty note into the provider, and it is this new note
- * that is being edited.
+ * Writes the edits to the provider. The note has been edited if an existing note
+ * was retrieved into the editor *or* if a new note was inserted.
+ * In the latter case, onCreate() inserted a new empty note into the provider,
+ * and it is this new note that is being edited.
*/
- } else if (mState == STATE_EDIT) {
- // Creates a map to contain the new values for the columns
- updateNote(text, null);
- } else if (mState == STATE_INSERT) {
- updateNote(text, text);
- mState = STATE_EDIT;
- }
+ } else if (mState == STATE_EDIT) {
+ // Creates a map to contain the new values for the columns
+ updateNote(text, null);
+ } else if (mState == STATE_INSERT) {
+ updateNote(text, text);
+ mState = STATE_EDIT;
}
}
@@ -409,8 +341,16 @@ public class NoteEditor extends Activity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Check if note has changed and enable/disable the revert option
- int colNoteIndex = mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_NOTE);
- String savedNote = mCursor.getString(colNoteIndex);
+ Cursor cursor = getContentResolver().query(
+ mUri, // The URI for the note that is to be retrieved.
+ PROJECTION, // The columns to retrieve
+ null, // No selection criteria are used, so no where columns are needed.
+ null, // No where columns are used, so no where values are needed.
+ null // No sort order is needed.
+ );
+ cursor.moveToFirst();
+ int colNoteIndex = cursor.getColumnIndex(Notes.COLUMN_NAME_NOTE);
+ String savedNote = cursor.getString(colNoteIndex);
String currentNote = mText.getText().toString();
if (savedNote.equals(currentNote)) {
menu.findItem(R.id.menu_revert).setVisible(false);
@@ -493,8 +433,8 @@ public class NoteEditor extends Activity {
// (moveToFirst() returns true), then this gets the note data from it.
if (orig != null) {
if (orig.moveToFirst()) {
- int colNoteIndex = mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_NOTE);
- int colTitleIndex = mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_TITLE);
+ int colNoteIndex = orig.getColumnIndex(NotePad.Notes.COLUMN_NAME_NOTE);
+ int colTitleIndex = orig.getColumnIndex(NotePad.Notes.COLUMN_NAME_TITLE);
text = orig.getString(colNoteIndex);
title = orig.getString(colTitleIndex);
}
@@ -571,13 +511,11 @@ public class NoteEditor extends Activity {
* android.content.AsyncQueryHandler or android.os.AsyncTask.
*/
getContentResolver().update(
- mUri, // The URI for the record to update.
- values, // The map of column names and new values to apply to them.
- null, // No selection criteria are used, so no where columns are necessary.
- null // No where columns are used, so no where arguments are necessary.
- );
-
-
+ mUri, // The URI for the record to update.
+ values, // The map of column names and new values to apply to them.
+ null, // No selection criteria are used, so no where columns are necessary.
+ null // No where columns are used, so no where arguments are necessary.
+ );
}
/**
@@ -585,19 +523,17 @@ public class NoteEditor extends Activity {
* newly created, or reverts to the original text of the note i
*/
private final void cancelNote() {
- if (mCursor != null) {
- if (mState == STATE_EDIT) {
- // Put the original note text back into the database
- mCursor.close();
- mCursor = null;
- ContentValues values = new ContentValues();
- values.put(NotePad.Notes.COLUMN_NAME_NOTE, mOriginalContent);
- getContentResolver().update(mUri, values, null, null);
- } else if (mState == STATE_INSERT) {
- // We inserted an empty note, make sure to delete it
- deleteNote();
- }
+
+ if (mState == STATE_EDIT) {
+ // Put the original note text back into the database
+ ContentValues values = new ContentValues();
+ values.put(NotePad.Notes.COLUMN_NAME_NOTE, mOriginalContent);
+ getContentResolver().update(mUri, values, null, null);
+ } else if (mState == STATE_INSERT) {
+ // We inserted an empty note, make sure to delete it
+ deleteNote();
}
+
setResult(RESULT_CANCELED);
finish();
}
@@ -606,11 +542,50 @@ public class NoteEditor extends Activity {
* Take care of deleting a note. Simply deletes the entry.
*/
private final void deleteNote() {
- if (mCursor != null) {
- mCursor.close();
- mCursor = null;
- getContentResolver().delete(mUri, null, null);
- mText.setText("");
+ getContentResolver().delete(mUri, null, null);
+ mText.setText("");
+ }
+
+ // LoaderManager callbacks
+ @Override
+ public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
+ return new CursorLoader(
+ this,
+ mUri, // The URI for the note that is to be retrieved.
+ PROJECTION, // The columns to retrieve
+ null, // No selection criteria are used, so no where columns are needed.
+ null, // No where columns are used, so no where values are needed.
+ null // No sort order is needed.
+ );
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
+
+ // Modifies the window title for the Activity according to the current Activity state.
+ if (cursor != null && cursor.moveToFirst() && mState == STATE_EDIT) {
+ // Set the title of the Activity to include the note title
+ int colTitleIndex = cursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_TITLE);
+ int colNoteIndex = cursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_NOTE);
+
+ // Gets the title and sets it
+ String title = cursor.getString(colTitleIndex);
+ Resources res = getResources();
+ String text = String.format(res.getString(R.string.title_edit), title);
+ setTitle(text);
+
+ // Gets the note text from the Cursor and puts it in the TextView, but doesn't change
+ // the text cursor's position.
+
+ String note = cursor.getString(colNoteIndex);
+ mText.setTextKeepState(note);
+ // Stores the original note text, to allow the user to revert changes.
+ if (mOriginalContent == null) {
+ mOriginalContent = note;
+ }
}
}
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> cursorLoader) {}
}
diff --git a/samples/NotePad/src/com/example/android/notepad/NotePadProvider.java b/samples/NotePad/src/com/example/android/notepad/NotePadProvider.java
index 183964563..f81e22d1f 100644
--- a/samples/NotePad/src/com/example/android/notepad/NotePadProvider.java
+++ b/samples/NotePad/src/com/example/android/notepad/NotePadProvider.java
@@ -71,11 +71,6 @@ public class NotePadProvider extends ContentProvider implements PipeDataWriter<C
private static HashMap<String, String> sNotesProjectionMap;
/**
- * A projection map used to select columns from the database
- */
- private static HashMap<String, String> sLiveFolderProjectionMap;
-
- /**
* Standard projection for the interesting columns of a normal note.
*/
private static final String[] READ_NOTE_PROJECTION = new String[] {
@@ -96,9 +91,6 @@ public class NotePadProvider extends ContentProvider implements PipeDataWriter<C
// The incoming URI matches the Note ID URI pattern
private static final int NOTE_ID = 2;
- // The incoming URI matches the Live Folder URI pattern
- private static final int LIVE_FOLDER_NOTES = 3;
-
/**
* A UriMatcher instance
*/
@@ -126,10 +118,6 @@ public class NotePadProvider extends ContentProvider implements PipeDataWriter<C
// to a note ID operation
sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);
- // Add a pattern that routes URIs terminated with live_folders/notes to a
- // live folder operation
- sUriMatcher.addURI(NotePad.AUTHORITY, "live_folders/notes", LIVE_FOLDER_NOTES);
-
/*
* Creates and initializes a projection map that returns all columns
*/
@@ -155,20 +143,6 @@ public class NotePadProvider extends ContentProvider implements PipeDataWriter<C
sNotesProjectionMap.put(
NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE,
NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE);
-
- /*
- * Creates an initializes a projection map for handling Live Folders
- */
-
- // Creates a new projection map instance
- sLiveFolderProjectionMap = new HashMap<String, String>();
-
- // Maps "_ID" to "_ID AS _ID" for a live folder
- sLiveFolderProjectionMap.put(LiveFolders._ID, NotePad.Notes._ID + " AS " + LiveFolders._ID);
-
- // Maps "NAME" to "title AS NAME"
- sLiveFolderProjectionMap.put(LiveFolders.NAME, NotePad.Notes.COLUMN_NAME_TITLE + " AS " +
- LiveFolders.NAME);
}
/**
@@ -278,11 +252,6 @@ public class NotePadProvider extends ContentProvider implements PipeDataWriter<C
uri.getPathSegments().get(NotePad.Notes.NOTE_ID_PATH_POSITION));
break;
- case LIVE_FOLDER_NOTES:
- // If the incoming URI is from a live folder, chooses the live folder projection.
- qb.setProjectionMap(sLiveFolderProjectionMap);
- break;
-
default:
// If the URI doesn't match any of the known patterns, throw an exception.
throw new IllegalArgumentException("Unknown URI " + uri);
@@ -339,7 +308,6 @@ public class NotePadProvider extends ContentProvider implements PipeDataWriter<C
// If the pattern is for notes or live folders, returns the general content type.
case NOTES:
- case LIVE_FOLDER_NOTES:
return NotePad.Notes.CONTENT_TYPE;
// If the pattern is for note IDs, returns the note ID content type.
@@ -380,7 +348,6 @@ public class NotePadProvider extends ContentProvider implements PipeDataWriter<C
// If the pattern is for notes or live folders, return null. Data streams are not
// supported for this type of URI.
case NOTES:
- case LIVE_FOLDER_NOTES:
return null;
// If the pattern is for note IDs and the MIME filter is text/plain, then return
@@ -635,7 +602,7 @@ public class NotePadProvider extends ContentProvider implements PipeDataWriter<C
throw new IllegalArgumentException("Unknown URI " + uri);
}
- /*Gets a handle to the content resolver object for the current context, and notifies it
+ /* Gets a handle to the content resolver object for the current context, and notifies it
* that the incoming URI changed. The object passes this along to the resolver framework,
* and observers that have registered themselves for the provider are notified.
*/
@@ -728,7 +695,7 @@ public class NotePadProvider extends ContentProvider implements PipeDataWriter<C
throw new IllegalArgumentException("Unknown URI " + uri);
}
- /*Gets a handle to the content resolver object for the current context, and notifies it
+ /* Gets a handle to the content resolver object for the current context, and notifies it
* that the incoming URI changed. The object passes this along to the resolver framework,
* and observers that have registered themselves for the provider are notified.
*/
diff --git a/samples/NotePad/src/com/example/android/notepad/NotesList.java b/samples/NotePad/src/com/example/android/notepad/NotesList.java
index 7e91f646c..bc21a7081 100644
--- a/samples/NotePad/src/com/example/android/notepad/NotesList.java
+++ b/samples/NotePad/src/com/example/android/notepad/NotesList.java
@@ -16,15 +16,16 @@
package com.example.android.notepad;
-import com.example.android.notepad.NotePad;
-
import android.app.ListActivity;
+import android.app.LoaderManager;
import android.content.ClipboardManager;
import android.content.ClipData;
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.Context;
+import android.content.CursorLoader;
import android.content.Intent;
+import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -36,6 +37,7 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
+import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
@@ -43,17 +45,14 @@ import android.widget.SimpleCursorAdapter;
* Displays a list of notes. Will display notes from the {@link Uri}
* provided in the incoming Intent if there is one, otherwise it defaults to displaying the
* contents of the {@link NotePadProvider}.
- *
- * NOTE: Notice that the provider operations in this Activity are taking place on the UI thread.
- * This is not a good practice. It is only done here to make the code more readable. A real
- * application should use the {@link android.content.AsyncQueryHandler} or
- * {@link android.os.AsyncTask} object to perform operations asynchronously on a separate thread.
*/
-public class NotesList extends ListActivity {
+public class NotesList extends ListActivity implements LoaderManager.LoaderCallbacks<Cursor> {
// For logging and debugging
private static final String TAG = "NotesList";
+ private static final int LOADER_ID = 0;
+
/**
* The columns needed by the cursor adapter
*/
@@ -65,6 +64,8 @@ public class NotesList extends ListActivity {
/** The index of the title column */
private static final int COLUMN_INDEX_TITLE = 1;
+ private SimpleCursorAdapter mAdapter;
+
/**
* onCreate is called when Android starts this Activity from scratch.
*/
@@ -95,18 +96,6 @@ public class NotesList extends ListActivity {
*/
getListView().setOnCreateContextMenuListener(this);
- /* Performs a managed query. The Activity handles closing and requerying the cursor
- * when needed.
- *
- * Please see the introductory note about performing provider operations on the UI thread.
- */
- Cursor cursor = managedQuery(
- getIntent().getData(), // Use the default content URI for the provider.
- PROJECTION, // Return the note ID and title for each note.
- null, // No where clause, return all records.
- null, // No where clause, therefore no where column values.
- NotePad.Notes.DEFAULT_SORT_ORDER // Use the default sort order.
- );
/*
* The following two arrays create a "map" between columns in the cursor and view IDs
@@ -124,17 +113,19 @@ public class NotesList extends ListActivity {
int[] viewIDs = { android.R.id.text1 };
// Creates the backing adapter for the ListView.
- SimpleCursorAdapter adapter
- = new SimpleCursorAdapter(
- this, // The Context for the ListView
- R.layout.noteslist_item, // Points to the XML for a list item
- cursor, // The cursor to get items from
- dataColumns,
- viewIDs
- );
+ mAdapter = new SimpleCursorAdapter(
+ this, // The Context for the ListView
+ R.layout.noteslist_item, // Points to the XML for a list item
+ null, // The cursor is set by CursorLoader when loaded
+ dataColumns,
+ viewIDs,
+ CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER
+ );
// Sets the ListView's adapter to be the cursor adapter that was just created.
- setListAdapter(adapter);
+ setListAdapter(mAdapter);
+ // Initialize the LoaderManager and start the query
+ getLoaderManager().initLoader(LOADER_ID, null, this);
}
/**
@@ -464,4 +455,28 @@ public class NotesList extends ListActivity {
startActivity(new Intent(Intent.ACTION_EDIT, uri));
}
}
+
+ // LoaderManager callbacks
+ @Override
+ public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
+ return new CursorLoader(
+ this,
+ getIntent().getData(), // Use the default content URI for the provider.
+ PROJECTION, // Return the note ID and title for each note.
+ null, // No where clause, return all records.
+ null, // No where clause, therefore no where column values.
+ NotePad.Notes.DEFAULT_SORT_ORDER // Use the default sort order.
+ );
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
+ mAdapter.changeCursor(cursor);
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> cursorLoader) {
+ // Since the Loader is reset, this removes the cursor reference from the adapter.
+ mAdapter.changeCursor(null);
+ }
}
diff --git a/samples/NotePad/src/com/example/android/notepad/NotesLiveFolder.java b/samples/NotePad/src/com/example/android/notepad/NotesLiveFolder.java
deleted file mode 100644
index 24afaa0d4..000000000
--- a/samples/NotePad/src/com/example/android/notepad/NotesLiveFolder.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2009 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.notepad;
-
-import com.example.android.notepad.NotePad;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.content.Intent.ShortcutIconResource;
-import android.os.Bundle;
-import android.provider.LiveFolders;
-
-/**
- * This Activity creates a live folder Intent and
- * sends it back to HOME. From the data in the Intent, HOME creates a live folder and displays
- * its icon in the Home view.
- * When the user clicks the icon, Home uses the data it got from the Intent to retrieve information
- * from a content provider and display it in a View.
- *
- * The intent filter for this Activity is set to ACTION_CREATE_LIVE_FOLDER, which
- * HOME sends in response to a long press and selection of Live Folder.
- */
-public class NotesLiveFolder extends Activity {
-
- /**
- * All of the work is done in onCreate(). The Activity doesn't actually display a UI.
- * Instead, it sets up an Intent and returns it to its caller (the HOME activity).
- */
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- /*
- * Gets the incoming Intent and its action. If the incoming Intent was
- * ACTION_CREATE_LIVE_FOLDER, then create an outgoing Intent with the
- * necessary data and send back OK. Otherwise, send back CANCEL.
- */
- final Intent intent = getIntent();
- final String action = intent.getAction();
-
- if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) {
-
- // Creates a new Intent.
- final Intent liveFolderIntent = new Intent();
-
- /*
- * The following statements put data into the outgoing Intent. Please see
- * {@link android.provider.LiveFolders for a detailed description of these
- * data values. From this data, HOME sets up a live folder.
- */
- // Sets the URI pattern for the content provider backing the folder.
- liveFolderIntent.setData(NotePad.Notes.LIVE_FOLDER_URI);
-
- // Adds the display name of the live folder as an Extra string.
- String foldername = getString(R.string.live_folder_name);
- liveFolderIntent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, foldername);
-
- // Adds the display icon of the live folder as an Extra resource.
- ShortcutIconResource foldericon =
- Intent.ShortcutIconResource.fromContext(this, R.drawable.live_folder_notes);
- liveFolderIntent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON, foldericon);
-
- // Add the display mode of the live folder as an integer. The specified
- // mode causes the live folder to display as a list.
- liveFolderIntent.putExtra(
- LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE,
- LiveFolders.DISPLAY_MODE_LIST);
-
- /*
- * Adds a base action for items in the live folder list, as an Intent. When the
- * user clicks an individual note in the list, the live folder fires this Intent.
- *
- * Its action is ACTION_EDIT, so it triggers the Note Editor activity. Its
- * data is the URI pattern for a single note identified by its ID. The live folder
- * automatically adds the ID value of the selected item to the URI pattern.
- *
- * As a result, Note Editor is triggered and gets a single note to retrieve by ID.
- */
- Intent returnIntent
- = new Intent(Intent.ACTION_EDIT, NotePad.Notes.CONTENT_ID_URI_PATTERN);
- liveFolderIntent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_BASE_INTENT, returnIntent);
-
- /* Creates an ActivityResult object to propagate back to HOME. Set its result indicator
- * to OK, and sets the returned Intent to the live folder Intent that was just
- * constructed.
- */
- setResult(RESULT_OK, liveFolderIntent);
-
- } else {
-
- // If the original action was not ACTION_CREATE_LIVE_FOLDER, creates an
- // ActivityResult with the indicator set to CANCELED, but do not return an Intent
- setResult(RESULT_CANCELED);
- }
-
- // Closes the Activity. The ActivityObject is propagated back to the caller.
- finish();
- }
-}
diff --git a/samples/NotePad/src/com/example/android/notepad/TitleEditor.java b/samples/NotePad/src/com/example/android/notepad/TitleEditor.java
index 5abe97b39..e6f029b98 100644
--- a/samples/NotePad/src/com/example/android/notepad/TitleEditor.java
+++ b/samples/NotePad/src/com/example/android/notepad/TitleEditor.java
@@ -21,8 +21,10 @@ import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
+import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
+import android.widget.Toast;
/**
* This Activity allows the user to edit a note's title. It displays a floating window
@@ -49,15 +51,15 @@ public class TitleEditor extends Activity {
// The position of the title column in a Cursor returned by the provider.
private static final int COLUMN_INDEX_TITLE = 1;
- // A Cursor object that will contain the results of querying the provider for a note.
- private Cursor mCursor;
-
// An EditText object for preserving the edited title.
private EditText mText;
// A URI object for the note whose title is being edited.
private Uri mUri;
+ // The title that was last saved.
+ private String mSavedTitle;
+
/**
* This method is called by Android when the Activity is first started. From the incoming
* Intent, it determines what kind of editing is desired, and then does it.
@@ -69,6 +71,9 @@ public class TitleEditor extends Activity {
// Set the View for this Activity object's UI.
setContentView(R.layout.title_editor);
+ // Gets the View ID for the EditText box
+ mText = (EditText) this.findViewById(R.id.title);
+
// Get the Intent that activated this Activity, and from it get the URI of the note whose
// title we need to edit.
mUri = getIntent().getData();
@@ -82,7 +87,7 @@ public class TitleEditor extends Activity {
* android.content.AsyncQueryHandler or android.os.AsyncTask.
*/
- mCursor = managedQuery(
+ Cursor cursor = getContentResolver().query(
mUri, // The URI for the note that is to be retrieved.
PROJECTION, // The columns to retrieve
null, // No selection criteria are used, so no where columns are needed.
@@ -90,8 +95,15 @@ public class TitleEditor extends Activity {
null // No sort order is needed.
);
- // Gets the View ID for the EditText box
- mText = (EditText) this.findViewById(R.id.title);
+ if (cursor != null) {
+
+ // The Cursor was just retrieved, so its index is set to one record *before* the first
+ // record retrieved. This moves it to the first record.
+ cursor.moveToFirst();
+
+ // Displays the current title text in the EditText object.
+ mText.setText(cursor.getString(COLUMN_INDEX_TITLE));
+ }
}
/**
@@ -103,65 +115,83 @@ public class TitleEditor extends Activity {
@Override
protected void onResume() {
super.onResume();
-
- // Verifies that the query made in onCreate() actually worked. If it worked, then the
- // Cursor object is not null. If it is *empty*, then mCursor.getCount() == 0.
- if (mCursor != null) {
-
- // The Cursor was just retrieved, so its index is set to one record *before* the first
- // record retrieved. This moves it to the first record.
- mCursor.moveToFirst();
-
- // Displays the current title text in the EditText object.
- mText.setText(mCursor.getString(COLUMN_INDEX_TITLE));
- }
}
/**
* This method is called when the Activity loses focus.
*
- * For Activity objects that edit information, onPause() may be the one place where changes are
- * saved. The Android application model is predicated on the idea that "save" and "exit" aren't
- * required actions. When users navigate away from an Activity, they shouldn't have to go back
- * to it to complete their work. The act of going away should save everything and leave the
- * Activity in a state where Android can destroy it if necessary.
- *
- * Updates the note with the text currently in the text box.
+ * While there is no need to override this method in this app, it is shown here to highlight
+ * that we are not saving any state in onPause, but have moved app state saving to onStop
+ * callback.
+ * In earlier versions of this app and popular literature it had been shown that onPause is good
+ * place to persist any unsaved work, however, this is not really a good practice because of how
+ * application and process lifecycle behave.
+ * As a general guideline apps should have a way of saving their business logic that does not
+ * solely rely on Activity (or other component) lifecyle state transitions.
+ * As a backstop you should save any app state, not saved during lifetime of the Activity, in
+ * onStop().
+ * For a more detailed explanation of this recommendation please read
+ * <a href = "https://developer.android.com/guide/topics/processes/process-lifecycle.html">
+ * Processes and Application Life Cycle </a>.
+ * <a href="https://developer.android.com/training/basics/activity-lifecycle/pausing.html">
+ * Pausing and Resuming an Activity </a>.
*/
@Override
protected void onPause() {
super.onPause();
+ }
- // Verifies that the query made in onCreate() actually worked. If it worked, then the
- // Cursor object is not null. If it is *empty*, then mCursor.getCount() == 0.
-
- if (mCursor != null) {
-
- // Creates a values map for updating the provider.
- ContentValues values = new ContentValues();
-
- // In the values map, sets the title to the current contents of the edit box.
- values.put(NotePad.Notes.COLUMN_NAME_TITLE, mText.getText().toString());
-
- /*
- * Updates the provider with the note's new title.
- *
- * Note: This is being done on the UI thread. It will block the thread until the
- * update completes. In a sample app, going against a simple provider based on a
- * local database, the block will be momentary, but in a real app you should use
- * android.content.AsyncQueryHandler or android.os.AsyncTask.
- */
- getContentResolver().update(
- mUri, // The URI for the note to update.
- values, // The values map containing the columns to update and the values to use.
- null, // No selection criteria is used, so no "where" columns are needed.
- null // No "where" columns are used, so no "where" values are needed.
- );
-
- }
+ /**
+ * This method is called when the Activity becomes invisible.
+ *
+ * For Activity objects that edit information, onStop() may be the one place where changes are
+ * saved.
+ * Updates the note with the text currently in the text box.
+ */
+ @Override
+ protected void onStop() {
+ super.onStop();
+ saveTitle();
}
public void onClickOk(View v) {
+ saveTitle();
finish();
}
+
+ // Saves the title if required
+ private void saveTitle() {
+
+ if (!TextUtils.isEmpty(mText.getText())) {
+
+ String newTitle = mText.getText().toString();
+
+ if (!newTitle.equals(mSavedTitle)) {
+ // Creates a values map for updating the provider.
+ ContentValues values = new ContentValues();
+
+ // In the values map, sets the title to the current contents of the edit box.
+ values.put(NotePad.Notes.COLUMN_NAME_TITLE, newTitle);
+
+ /*
+ * Updates the provider with the note's new title.
+ *
+ * Note: This is being done on the UI thread. It will block the thread until the
+ * update completes. In a sample app, going against a simple provider based on a
+ * local database, the block will be momentary, but in a real app you should use
+ * android.content.AsyncQueryHandler or android.os.AsyncTask.
+ */
+ getContentResolver().update(
+ mUri, // The URI for the note to update.
+ values,
+ // The values map containing the columns to update and the values to use.
+ null, // No selection criteria is used, so no "where" columns are needed.
+ null // No "where" columns are used, so no "where" values are needed.
+ );
+ mSavedTitle = newTitle;
+ }
+ } else {
+ Toast.makeText(this, R.string.title_blank, Toast.LENGTH_SHORT).show();
+ }
+ }
}
diff --git a/samples/browseable/AccelerometerPlay/AndroidManifest.xml b/samples/browseable/AccelerometerPlay/AndroidManifest.xml
deleted file mode 100644
index 3c3ec2743..000000000
--- a/samples/browseable/AccelerometerPlay/AndroidManifest.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 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"
- android:versionCode="1"
- android:versionName="1.0" package="com.example.android.accelerometerplay">
- <application android:icon="@mipmap/ic_launcher" android:label="@string/app_name">
- <activity android:name=".AccelerometerPlayActivity"
- android:label="@string/app_name"
- android:screenOrientation="portrait"
- android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
-
- </application>
-
-
-<uses-sdk android:minSdkVersion="5"></uses-sdk>
-<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
-
-<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
-
-</manifest>
diff --git a/samples/browseable/AccelerometerPlay/_index.jd b/samples/browseable/AccelerometerPlay/_index.jd
deleted file mode 100644
index 5e09e2d14..000000000
--- a/samples/browseable/AccelerometerPlay/_index.jd
+++ /dev/null
@@ -1,15 +0,0 @@
-
-page.tags="AccelerometerPlay"
-sample.group=Sensors
-@jd:body
-
-<p>
-
- <p>This sample demonstrates how to use an accelerometer sensor as input for
- a physics-based view. The input from the accelerometer is used to simulate a
- virtual surface, and a number of free-moving objects placed on top of it.</p>
-
- <p>Any effects from the device's acceleration vector (including both gravity and
- temporary movement) will be translated to the on-screen particles.</p>
-
- </p>
diff --git a/samples/browseable/AccelerometerPlay/res/drawable-hdpi/ball.png b/samples/browseable/AccelerometerPlay/res/drawable-hdpi/ball.png
deleted file mode 100644
index e79e4d615..000000000
--- a/samples/browseable/AccelerometerPlay/res/drawable-hdpi/ball.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AccelerometerPlay/res/drawable-hdpi/wood.jpg b/samples/browseable/AccelerometerPlay/res/drawable-hdpi/wood.jpg
deleted file mode 100644
index 883f491d9..000000000
--- a/samples/browseable/AccelerometerPlay/res/drawable-hdpi/wood.jpg
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AccelerometerPlay/res/layout/main.xml b/samples/browseable/AccelerometerPlay/res/layout/main.xml
deleted file mode 100644
index c69b22294..000000000
--- a/samples/browseable/AccelerometerPlay/res/layout/main.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 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"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/wood"
- >
-</FrameLayout>
diff --git a/samples/browseable/AccelerometerPlay/res/mipmap-hdpi/ic_launcher.png b/samples/browseable/AccelerometerPlay/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 800c55629..000000000
--- a/samples/browseable/AccelerometerPlay/res/mipmap-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AccelerometerPlay/res/mipmap-mdpi/ic_launcher.png b/samples/browseable/AccelerometerPlay/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 1d6e9e55f..000000000
--- a/samples/browseable/AccelerometerPlay/res/mipmap-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AccelerometerPlay/res/mipmap-xhdpi/ic_launcher.png b/samples/browseable/AccelerometerPlay/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index 2989356b5..000000000
--- a/samples/browseable/AccelerometerPlay/res/mipmap-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AccelerometerPlay/res/mipmap-xxhdpi/ic_launcher.png b/samples/browseable/AccelerometerPlay/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 56b87a28d..000000000
--- a/samples/browseable/AccelerometerPlay/res/mipmap-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AccelerometerPlay/res/mipmap-xxxhdpi/ic_launcher.png b/samples/browseable/AccelerometerPlay/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 500543319..000000000
--- a/samples/browseable/AccelerometerPlay/res/mipmap-xxxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AccelerometerPlay/res/values/strings.xml b/samples/browseable/AccelerometerPlay/res/values/strings.xml
deleted file mode 100644
index 6e3785e94..000000000
--- a/samples/browseable/AccelerometerPlay/res/values/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 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">AccelerometerPlay</string>
-</resources>
diff --git a/samples/browseable/AccelerometerPlay/src/com.example.android.accelerometerplay/AccelerometerPlayActivity.java b/samples/browseable/AccelerometerPlay/src/com.example.android.accelerometerplay/AccelerometerPlayActivity.java
deleted file mode 100644
index b15685261..000000000
--- a/samples/browseable/AccelerometerPlay/src/com.example.android.accelerometerplay/AccelerometerPlayActivity.java
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * Copyright (C) 2010 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.accelerometerplay;
-
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.BitmapFactory.Options;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.view.Display;
-import android.view.Surface;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-
-/**
- * This is an example of using the accelerometer to integrate the device's
- * acceleration to a position using the Verlet method. This is illustrated with
- * a very simple particle system comprised of a few iron balls freely moving on
- * an inclined wooden table. The inclination of the virtual table is controlled
- * by the device's accelerometer.
- *
- * @see SensorManager
- * @see SensorEvent
- * @see Sensor
- */
-
-public class AccelerometerPlayActivity extends Activity {
-
- private SimulationView mSimulationView;
- private SensorManager mSensorManager;
- private PowerManager mPowerManager;
- private WindowManager mWindowManager;
- private Display mDisplay;
- private WakeLock mWakeLock;
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Get an instance of the SensorManager
- mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
-
- // Get an instance of the PowerManager
- mPowerManager = (PowerManager) getSystemService(POWER_SERVICE);
-
- // Get an instance of the WindowManager
- mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
- mDisplay = mWindowManager.getDefaultDisplay();
-
- // Create a bright wake lock
- mWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, getClass()
- .getName());
-
- // instantiate our simulation view and set it as the activity's content
- mSimulationView = new SimulationView(this);
- mSimulationView.setBackgroundResource(R.drawable.wood);
- setContentView(mSimulationView);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- /*
- * when the activity is resumed, we acquire a wake-lock so that the
- * screen stays on, since the user will likely not be fiddling with the
- * screen or buttons.
- */
- mWakeLock.acquire();
-
- // Start the simulation
- mSimulationView.startSimulation();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- /*
- * When the activity is paused, we make sure to stop the simulation,
- * release our sensor resources and wake locks
- */
-
- // Stop the simulation
- mSimulationView.stopSimulation();
-
- // and release our wake-lock
- mWakeLock.release();
- }
-
- class SimulationView extends FrameLayout implements SensorEventListener {
- // diameter of the balls in meters
- private static final float sBallDiameter = 0.004f;
- private static final float sBallDiameter2 = sBallDiameter * sBallDiameter;
-
- private final int mDstWidth;
- private final int mDstHeight;
-
- private Sensor mAccelerometer;
- private long mLastT;
-
- private float mXDpi;
- private float mYDpi;
- private float mMetersToPixelsX;
- private float mMetersToPixelsY;
- private float mXOrigin;
- private float mYOrigin;
- private float mSensorX;
- private float mSensorY;
- private float mHorizontalBound;
- private float mVerticalBound;
- private final ParticleSystem mParticleSystem;
- /*
- * Each of our particle holds its previous and current position, its
- * acceleration. for added realism each particle has its own friction
- * coefficient.
- */
- class Particle extends View {
- private float mPosX = (float) Math.random();
- private float mPosY = (float) Math.random();
- private float mVelX;
- private float mVelY;
-
- public Particle(Context context) {
- super(context);
- }
-
- public Particle(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public Particle(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public Particle(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- public void computePhysics(float sx, float sy, float dT) {
-
- final float ax = -sx/5;
- final float ay = -sy/5;
-
- mPosX += mVelX * dT + ax * dT * dT / 2;
- mPosY += mVelY * dT + ay * dT * dT / 2;
-
- mVelX += ax * dT;
- mVelY += ay * dT;
- }
-
- /*
- * Resolving constraints and collisions with the Verlet integrator
- * can be very simple, we simply need to move a colliding or
- * constrained particle in such way that the constraint is
- * satisfied.
- */
- public void resolveCollisionWithBounds() {
- final float xmax = mHorizontalBound;
- final float ymax = mVerticalBound;
- final float x = mPosX;
- final float y = mPosY;
- if (x > xmax) {
- mPosX = xmax;
- mVelX = 0;
- } else if (x < -xmax) {
- mPosX = -xmax;
- mVelX = 0;
- }
- if (y > ymax) {
- mPosY = ymax;
- mVelY = 0;
- } else if (y < -ymax) {
- mPosY = -ymax;
- mVelY = 0;
- }
- }
- }
-
- /*
- * A particle system is just a collection of particles
- */
- class ParticleSystem {
- static final int NUM_PARTICLES = 5;
- private Particle mBalls[] = new Particle[NUM_PARTICLES];
-
- ParticleSystem() {
- /*
- * Initially our particles have no speed or acceleration
- */
- for (int i = 0; i < mBalls.length; i++) {
- mBalls[i] = new Particle(getContext());
- mBalls[i].setBackgroundResource(R.drawable.ball);
- mBalls[i].setLayerType(LAYER_TYPE_HARDWARE, null);
- addView(mBalls[i], new ViewGroup.LayoutParams(mDstWidth, mDstHeight));
- }
- }
-
- /*
- * Update the position of each particle in the system using the
- * Verlet integrator.
- */
- private void updatePositions(float sx, float sy, long timestamp) {
- final long t = timestamp;
- if (mLastT != 0) {
- final float dT = (float) (t - mLastT) / 1000.f /** (1.0f / 1000000000.0f)*/;
- final int count = mBalls.length;
- for (int i = 0; i < count; i++) {
- Particle ball = mBalls[i];
- ball.computePhysics(sx, sy, dT);
- }
- }
- mLastT = t;
- }
-
- /*
- * Performs one iteration of the simulation. First updating the
- * position of all the particles and resolving the constraints and
- * collisions.
- */
- public void update(float sx, float sy, long now) {
- // update the system's positions
- updatePositions(sx, sy, now);
-
- // We do no more than a limited number of iterations
- final int NUM_MAX_ITERATIONS = 10;
-
- /*
- * Resolve collisions, each particle is tested against every
- * other particle for collision. If a collision is detected the
- * particle is moved away using a virtual spring of infinite
- * stiffness.
- */
- boolean more = true;
- final int count = mBalls.length;
- for (int k = 0; k < NUM_MAX_ITERATIONS && more; k++) {
- more = false;
- for (int i = 0; i < count; i++) {
- Particle curr = mBalls[i];
- for (int j = i + 1; j < count; j++) {
- Particle ball = mBalls[j];
- float dx = ball.mPosX - curr.mPosX;
- float dy = ball.mPosY - curr.mPosY;
- float dd = dx * dx + dy * dy;
- // Check for collisions
- if (dd <= sBallDiameter2) {
- /*
- * add a little bit of entropy, after nothing is
- * perfect in the universe.
- */
- dx += ((float) Math.random() - 0.5f) * 0.0001f;
- dy += ((float) Math.random() - 0.5f) * 0.0001f;
- dd = dx * dx + dy * dy;
- // simulate the spring
- final float d = (float) Math.sqrt(dd);
- final float c = (0.5f * (sBallDiameter - d)) / d;
- final float effectX = dx * c;
- final float effectY = dy * c;
- curr.mPosX -= effectX;
- curr.mPosY -= effectY;
- ball.mPosX += effectX;
- ball.mPosY += effectY;
- more = true;
- }
- }
- curr.resolveCollisionWithBounds();
- }
- }
- }
-
- public int getParticleCount() {
- return mBalls.length;
- }
-
- public float getPosX(int i) {
- return mBalls[i].mPosX;
- }
-
- public float getPosY(int i) {
- return mBalls[i].mPosY;
- }
- }
-
- public void startSimulation() {
- /*
- * It is not necessary to get accelerometer events at a very high
- * rate, by using a slower rate (SENSOR_DELAY_UI), we get an
- * automatic low-pass filter, which "extracts" the gravity component
- * of the acceleration. As an added benefit, we use less power and
- * CPU resources.
- */
- mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
- }
-
- public void stopSimulation() {
- mSensorManager.unregisterListener(this);
- }
-
- public SimulationView(Context context) {
- super(context);
- mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
-
- DisplayMetrics metrics = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(metrics);
- mXDpi = metrics.xdpi;
- mYDpi = metrics.ydpi;
- mMetersToPixelsX = mXDpi / 0.0254f;
- mMetersToPixelsY = mYDpi / 0.0254f;
-
- // rescale the ball so it's about 0.5 cm on screen
- mDstWidth = (int) (sBallDiameter * mMetersToPixelsX + 0.5f);
- mDstHeight = (int) (sBallDiameter * mMetersToPixelsY + 0.5f);
- mParticleSystem = new ParticleSystem();
-
- Options opts = new Options();
- opts.inDither = true;
- opts.inPreferredConfig = Bitmap.Config.RGB_565;
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- // compute the origin of the screen relative to the origin of
- // the bitmap
- mXOrigin = (w - mDstWidth) * 0.5f;
- mYOrigin = (h - mDstHeight) * 0.5f;
- mHorizontalBound = ((w / mMetersToPixelsX - sBallDiameter) * 0.5f);
- mVerticalBound = ((h / mMetersToPixelsY - sBallDiameter) * 0.5f);
- }
-
- @Override
- public void onSensorChanged(SensorEvent event) {
- if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
- return;
- /*
- * record the accelerometer data, the event's timestamp as well as
- * the current time. The latter is needed so we can calculate the
- * "present" time during rendering. In this application, we need to
- * take into account how the screen is rotated with respect to the
- * sensors (which always return data in a coordinate space aligned
- * to with the screen in its native orientation).
- */
-
- switch (mDisplay.getRotation()) {
- case Surface.ROTATION_0:
- mSensorX = event.values[0];
- mSensorY = event.values[1];
- break;
- case Surface.ROTATION_90:
- mSensorX = -event.values[1];
- mSensorY = event.values[0];
- break;
- case Surface.ROTATION_180:
- mSensorX = -event.values[0];
- mSensorY = -event.values[1];
- break;
- case Surface.ROTATION_270:
- mSensorX = event.values[1];
- mSensorY = -event.values[0];
- break;
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- /*
- * Compute the new position of our object, based on accelerometer
- * data and present time.
- */
- final ParticleSystem particleSystem = mParticleSystem;
- final long now = System.currentTimeMillis();
- final float sx = mSensorX;
- final float sy = mSensorY;
-
- particleSystem.update(sx, sy, now);
-
- final float xc = mXOrigin;
- final float yc = mYOrigin;
- final float xs = mMetersToPixelsX;
- final float ys = mMetersToPixelsY;
- final int count = particleSystem.getParticleCount();
- for (int i = 0; i < count; i++) {
- /*
- * We transform the canvas so that the coordinate system matches
- * the sensors coordinate system with the origin in the center
- * of the screen and the unit is the meter.
- */
- final float x = xc + particleSystem.getPosX(i) * xs;
- final float y = yc - particleSystem.getPosY(i) * ys;
- particleSystem.mBalls[i].setTranslationX(x);
- particleSystem.mBalls[i].setTranslationY(y);
- }
-
- // and make sure to redraw asap
- invalidate();
- }
-
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- }
- }
-}
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/_index.jd b/samples/browseable/ActionBarCompat-ShareActionProvider/_index.jd
deleted file mode 100644
index d9df53688..000000000
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/_index.jd
+++ /dev/null
@@ -1,11 +0,0 @@
-
-page.tags="ActionBarCompat-ShareActionProvider"
-sample.group=UI
-@jd:body
-
-<p>
-
- This sample shows you how a provide a context-sensitive ShareActionProvider with
- ActionBarCompat, backwards compatible to API v7.
-
- </p>
diff --git a/samples/browseable/ActiveNotifications/res/values/strings.xml b/samples/browseable/ActiveNotifications/res/values/strings.xml
index a4275fdf2..783a0744b 100644
--- a/samples/browseable/ActiveNotifications/res/values/strings.xml
+++ b/samples/browseable/ActiveNotifications/res/values/strings.xml
@@ -16,8 +16,8 @@
-->
<resources>
<string name="add_a_notification">Add a notification</string>
- <string name="active_notifications">Active Notifications: %1$s</string>
+ <string name="active_notifications">Active Notifications: %1$d</string>
<string name="update_notification_count">Update count</string>
<string name="sample_notification_content">This is a sample notification.</string>
- <string name="sample_notification_summary_content">There are %s ActiveNotifications.</string>
+ <string name="sample_notification_summary_content">There are %d ActiveNotifications.</string>
</resources>
diff --git a/samples/browseable/ActiveNotifications/src/com.example.android.activenotifications/ActiveNotificationsFragment.java b/samples/browseable/ActiveNotifications/src/com.example.android.activenotifications/ActiveNotificationsFragment.java
index db0dbac6f..d752a36f2 100644
--- a/samples/browseable/ActiveNotifications/src/com.example.android.activenotifications/ActiveNotificationsFragment.java
+++ b/samples/browseable/ActiveNotifications/src/com.example.android.activenotifications/ActiveNotificationsFragment.java
@@ -129,23 +129,12 @@ public class ActiveNotificationsFragment extends Fragment {
* Adds/updates/removes the notification summary as necessary.
*/
protected void updateNotificationSummary() {
- final StatusBarNotification[] activeNotifications = mNotificationManager
- .getActiveNotifications();
-
- int numberOfNotifications = activeNotifications.length;
- // Since the notifications might include a summary notification remove it from the count if
- // it is present.
- for (StatusBarNotification notification : activeNotifications) {
- if (notification.getId() == NOTIFICATION_GROUP_SUMMARY_ID) {
- numberOfNotifications--;
- break;
- }
- }
+ int numberOfNotifications = getNumberOfNotifications();
if (numberOfNotifications > 1) {
// Add/update the notification summary.
String notificationContent = getString(R.string.sample_notification_summary_content,
- "" + numberOfNotifications);
+ numberOfNotifications);
final NotificationCompat.Builder builder = new NotificationCompat.Builder(getActivity())
.setSmallIcon(R.mipmap.ic_notification)
.setStyle(new NotificationCompat.BigTextStyle()
@@ -165,12 +154,7 @@ public class ActiveNotificationsFragment extends Fragment {
* display them to the user.
*/
protected void updateNumberOfNotifications() {
- // [BEGIN get_active_notifications]
- // Query the currently displayed notifications.
- final StatusBarNotification[] activeNotifications = mNotificationManager
- .getActiveNotifications();
- // [END get_active_notifications]
- final int numberOfNotifications = activeNotifications.length;
+ final int numberOfNotifications = getNumberOfNotifications();
mNumberOfNotifications.setText(getString(R.string.active_notifications,
numberOfNotifications));
Log.i(TAG, getString(R.string.active_notifications, numberOfNotifications));
@@ -190,4 +174,21 @@ public class ActiveNotificationsFragment extends Fragment {
}
return notificationId;
}
+
+ private int getNumberOfNotifications() {
+ // [BEGIN get_active_notifications]
+ // Query the currently displayed notifications.
+ final StatusBarNotification[] activeNotifications = mNotificationManager
+ .getActiveNotifications();
+ // [END get_active_notifications]
+
+ // Since the notifications might include a summary notification remove it from the count if
+ // it is present.
+ for (StatusBarNotification notification : activeNotifications) {
+ if (notification.getId() == NOTIFICATION_GROUP_SUMMARY_ID) {
+ return activeNotifications.length - 1;
+ }
+ }
+ return activeNotifications.length;
+ }
}
diff --git a/samples/browseable/AdvancedImmersiveMode/res/layout/fragment_flags.xml b/samples/browseable/AdvancedImmersiveMode/res/layout/fragment_flags.xml
index 2c74e83f0..c59b3b393 100644
--- a/samples/browseable/AdvancedImmersiveMode/res/layout/fragment_flags.xml
+++ b/samples/browseable/AdvancedImmersiveMode/res/layout/fragment_flags.xml
@@ -1,43 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical" android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/flag_enable_lowprof"
- android:text="Enable Low Profile Mode" />
+ android:text="@string/enable_low_profile_mode" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/flag_hide_navbar"
- android:text="Hide Navigation bar" />
+ android:text="@string/hide_navigation_bar" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/flag_hide_statbar"
- android:text="Hide Status Bar" />
+ android:text="@string/hide_status_bar" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/flag_enable_immersive"
- android:text="Enable Immersive Mode" />
+ android:text="@string/enable_immersive_mode" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/flag_enable_immersive_sticky"
- android:text="Enable Immersive Mode (Sticky)" />
+ android:text="@string/enable_immersive_mode_sticky" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Do things!"
+ android:text="@string/do_things"
android:id="@+id/btn_changeFlags" />
@@ -45,25 +46,24 @@
android:layout_marginTop="@dimen/margin_large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Common flag presets"/>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal" android:layout_width="match_parent"
+ android:text="@string/common_flag_presets" />
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Immersive Mode"
+ android:text="@string/immersive_mode"
android:id="@+id/btn_immersive" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Leanback Mode"
+ android:text="@string/leanback_mode"
android:id="@+id/btn_leanback" />
</LinearLayout>
-
-
-
</LinearLayout> \ No newline at end of file
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values/strings.xml b/samples/browseable/AdvancedImmersiveMode/res/values/strings.xml
new file mode 100644
index 000000000..6cfd28c78
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+ Copyright 2016 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="enable_low_profile_mode">Enable Low Profile Mode</string>
+ <string name="hide_navigation_bar">Hide Navigation bar</string>
+ <string name="hide_status_bar">Hide Status Bar</string>
+ <string name="enable_immersive_mode">Enable Immersive Mode</string>
+ <string name="enable_immersive_mode_sticky">Enable Immersive Mode (Sticky)</string>
+ <string name="do_things">Do things!</string>
+ <string name="common_flag_presets">Common flag presets</string>
+ <string name="immersive_mode">Immersive Mode</string>
+ <string name="leanback_mode">Leanback Mode</string>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/AgendaData/Application/AndroidManifest.xml b/samples/browseable/AgendaData/Application/AndroidManifest.xml
index ad6cccde8..083b223dd 100644
--- a/samples/browseable/AgendaData/Application/AndroidManifest.xml
+++ b/samples/browseable/AgendaData/Application/AndroidManifest.xml
@@ -18,7 +18,7 @@
package="com.example.android.wearable.agendadata">
<uses-sdk android:minSdkVersion="18"
- android:targetSdkVersion="23" />
+ android:targetSdkVersion="25" />
<!-- BEGIN_INCLUDE(manifest) -->
diff --git a/samples/browseable/AgendaData/Wearable/AndroidManifest.xml b/samples/browseable/AgendaData/Wearable/AndroidManifest.xml
index 87bed7061..f8bbdd80b 100644
--- a/samples/browseable/AgendaData/Wearable/AndroidManifest.xml
+++ b/samples/browseable/AgendaData/Wearable/AndroidManifest.xml
@@ -18,7 +18,7 @@
package="com.example.android.wearable.agendadata" >
<uses-sdk android:minSdkVersion="20"
- android:targetSdkVersion="23" />
+ android:targetSdkVersion="25" />
<uses-feature android:name="android.hardware.type.watch" />
@@ -28,6 +28,10 @@
>
<meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="false" />
+
+ <meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
diff --git a/samples/browseable/AlwaysOn/AndroidManifest.xml b/samples/browseable/AlwaysOn/AndroidManifest.xml
index 12c4b03a5..c105808c9 100644
--- a/samples/browseable/AlwaysOn/AndroidManifest.xml
+++ b/samples/browseable/AlwaysOn/AndroidManifest.xml
@@ -25,7 +25,12 @@
<application
android:allowBackup="false"
- android:label="@string/app_name">
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.DeviceDefault">
+
+ <meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="true" />
<!--If you want your app to run on pre-22, then set required to false -->
<uses-library android:name="com.google.android.wearable" android:required="false" />
diff --git a/samples/browseable/AppRestrictionEnforcer/AndroidManifest.xml b/samples/browseable/AppRestrictionEnforcer/AndroidManifest.xml
index c66b4b33e..1cd6ae851 100644
--- a/samples/browseable/AppRestrictionEnforcer/AndroidManifest.xml
+++ b/samples/browseable/AppRestrictionEnforcer/AndroidManifest.xml
@@ -16,15 +16,17 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
package="com.example.android.apprestrictionenforcer"
android:versionCode="1"
android:versionName="1.0">
<application
android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
+ android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
- android:theme="@style/AppTheme">
+ android:theme="@style/AppTheme"
+ tools:ignore="GoogleAppIndexingWarning">
<activity
android:name=".MainActivity"
diff --git a/samples/browseable/AppRestrictionEnforcer/_index.jd b/samples/browseable/AppRestrictionEnforcer/_index.jd
index ec7be7ccf..632cee2af 100644
--- a/samples/browseable/AppRestrictionEnforcer/_index.jd
+++ b/samples/browseable/AppRestrictionEnforcer/_index.jd
@@ -6,6 +6,6 @@ sample.group=Admin
<p>
This sample demonstrates how to set restrictions to other apps as a profile owner.
- Use AppRestrictionSchema sample as a app with available restrictions.
+ Use the AppRestrictionSchema sample to set restrictions.
</p>
diff --git a/samples/browseable/AppRestrictionEnforcer/res/drawable-hdpi/ic_launcher.png b/samples/browseable/AppRestrictionEnforcer/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index e7bd161ef..000000000
--- a/samples/browseable/AppRestrictionEnforcer/res/drawable-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AppRestrictionEnforcer/res/drawable-mdpi/ic_launcher.png b/samples/browseable/AppRestrictionEnforcer/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 4c42c9c45..000000000
--- a/samples/browseable/AppRestrictionEnforcer/res/drawable-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AppRestrictionEnforcer/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/AppRestrictionEnforcer/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 3ec336888..000000000
--- a/samples/browseable/AppRestrictionEnforcer/res/drawable-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AppRestrictionEnforcer/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/AppRestrictionEnforcer/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 730f80cd2..000000000
--- a/samples/browseable/AppRestrictionEnforcer/res/drawable-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AppRestrictionEnforcer/res/layout/fragment_setup_profile.xml b/samples/browseable/AppRestrictionEnforcer/res/layout/fragment_setup_profile.xml
index 8fde91fc3..c21939514 100644
--- a/samples/browseable/AppRestrictionEnforcer/res/layout/fragment_setup_profile.xml
+++ b/samples/browseable/AppRestrictionEnforcer/res/layout/fragment_setup_profile.xml
@@ -18,7 +18,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context="com.example.android.basicmanagedprofile.MainActivity.MainFragment">
+ tools:context="com.example.android.apprestrictionenforcer.MainActivity">
<LinearLayout
android:layout_width="match_parent"
diff --git a/samples/browseable/AppRestrictionEnforcer/res/layout/separator.xml b/samples/browseable/AppRestrictionEnforcer/res/layout/separator.xml
deleted file mode 100644
index 6927d801c..000000000
--- a/samples/browseable/AppRestrictionEnforcer/res/layout/separator.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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/samples/browseable/AppRestrictionEnforcer/res/mipmap-hdpi/ic_launcher.png b/samples/browseable/AppRestrictionEnforcer/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..7e0b8c8c3
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionEnforcer/res/mipmap-mdpi/ic_launcher.png b/samples/browseable/AppRestrictionEnforcer/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..963c36e1e
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionEnforcer/res/mipmap-xhdpi/ic_launcher.png b/samples/browseable/AppRestrictionEnforcer/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..6e0f52d5d
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionEnforcer/res/mipmap-xxhdpi/ic_launcher.png b/samples/browseable/AppRestrictionEnforcer/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..3ff049c1b
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionEnforcer/res/mipmap-xxxhdpi/ic_launcher.png b/samples/browseable/AppRestrictionEnforcer/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..9bf83de04
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionEnforcer/res/values/base-strings.xml b/samples/browseable/AppRestrictionEnforcer/res/values/base-strings.xml
index dbf51bdf6..9e3dc41da 100644
--- a/samples/browseable/AppRestrictionEnforcer/res/values/base-strings.xml
+++ b/samples/browseable/AppRestrictionEnforcer/res/values/base-strings.xml
@@ -22,7 +22,7 @@
This sample demonstrates how to set restrictions to other apps as a profile owner.
- Use AppRestrictionSchema sample as a app with available restrictions.
+ Use the AppRestrictionSchema sample to set restrictions.
]]>
diff --git a/samples/browseable/AppRestrictionEnforcer/res/values/strings.xml b/samples/browseable/AppRestrictionEnforcer/res/values/strings.xml
index 07e1c85c7..88fe8cc73 100644
--- a/samples/browseable/AppRestrictionEnforcer/res/values/strings.xml
+++ b/samples/browseable/AppRestrictionEnforcer/res/values/strings.xml
@@ -22,8 +22,6 @@
<string name="status_need_reinstall">AppRestrictionSchema needs reinstalling.</string>
<string name="unhide">Activate AppRestrictionSchema</string>
<string name="allow_saying_hello">Allow AppRestrictionSchema to say hello: </string>
- <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>
diff --git a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/Constants.java b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/Constants.java
index bb4e958c7..0f8a1e34b 100644
--- a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/Constants.java
+++ b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/Constants.java
@@ -21,7 +21,6 @@ public interface Constants {
/**
* Package name of the AppRestrictionSchema sample.
*/
- public static final String PACKAGE_NAME_APP_RESTRICTION_SCHEMA
- = "com.example.android.apprestrictionschema";
+ String PACKAGE_NAME_APP_RESTRICTION_SCHEMA = "com.example.android.apprestrictionschema";
}
diff --git a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/ItemAddFragment.java b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/ItemAddFragment.java
index 091a0a889..a5f6628a8 100644
--- a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/ItemAddFragment.java
+++ b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/ItemAddFragment.java
@@ -16,7 +16,6 @@
package com.example.android.apprestrictionenforcer;
-import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
diff --git a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/MainActivity.java b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/MainActivity.java
index 85eace96b..e250e7417 100644
--- a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/MainActivity.java
+++ b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/MainActivity.java
@@ -20,6 +20,7 @@ import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
@@ -38,9 +39,16 @@ public class MainActivity extends FragmentActivity implements StatusFragment.Sta
showSetupProfile();
} else {
try {
+ int packageFlags;
+ if (Build.VERSION.SDK_INT < 24) {
+ //noinspection deprecation
+ packageFlags = PackageManager.GET_UNINSTALLED_PACKAGES;
+ } else {
+ packageFlags = PackageManager.MATCH_UNINSTALLED_PACKAGES;
+ }
ApplicationInfo info = packageManager.getApplicationInfo(
Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA,
- PackageManager.GET_UNINSTALLED_PACKAGES);
+ packageFlags);
if (0 == (info.flags & ApplicationInfo.FLAG_INSTALLED)) {
// Need to reinstall the sample app
showStatusProfile();
diff --git a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/SetupProfileFragment.java b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/SetupProfileFragment.java
index 29c36d410..28bd1dad7 100644
--- a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/SetupProfileFragment.java
+++ b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/SetupProfileFragment.java
@@ -80,6 +80,7 @@ public class SetupProfileFragment extends Fragment implements View.OnClickListen
intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
EnforcerDeviceAdminReceiver.getComponentName(activity));
} else {
+ //noinspection deprecation
intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,
activity.getApplicationContext().getPackageName());
intent.putExtra(EXTRA_DEVICE_ADMIN, EnforcerDeviceAdminReceiver.getComponentName(activity));
diff --git a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/StatusFragment.java b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/StatusFragment.java
index f4a4eb796..ed3258071 100644
--- a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/StatusFragment.java
+++ b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/StatusFragment.java
@@ -20,6 +20,7 @@ import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
@@ -85,9 +86,16 @@ public class StatusFragment extends Fragment implements View.OnClickListener {
private void updateUi(Activity activity) {
PackageManager packageManager = activity.getPackageManager();
try {
+ int packageFlags;
+ if (Build.VERSION.SDK_INT < 24) {
+ //noinspection deprecation
+ packageFlags = PackageManager.GET_UNINSTALLED_PACKAGES;
+ } else {
+ packageFlags = PackageManager.MATCH_UNINSTALLED_PACKAGES;
+ }
ApplicationInfo info = packageManager.getApplicationInfo(
Constants.PACKAGE_NAME_APP_RESTRICTION_SCHEMA,
- PackageManager.GET_UNINSTALLED_PACKAGES);
+ packageFlags);
DevicePolicyManager devicePolicyManager =
(DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE);
if ((info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
diff --git a/samples/browseable/AppRestrictionSchema/AndroidManifest.xml b/samples/browseable/AppRestrictionSchema/AndroidManifest.xml
index f8bbccc56..6ef22ede6 100644
--- a/samples/browseable/AppRestrictionSchema/AndroidManifest.xml
+++ b/samples/browseable/AppRestrictionSchema/AndroidManifest.xml
@@ -16,17 +16,17 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
package="com.example.android.apprestrictionschema"
android:versionCode="1"
android:versionName="1.0">
- <!-- uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" /-->
-
<application
android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
+ android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
- android:theme="@style/AppTheme">
+ android:theme="@style/AppTheme"
+ tools:ignore="GoogleAppIndexingWarning">
<meta-data
android:name="android.content.APP_RESTRICTIONS"
diff --git a/samples/browseable/AppRestrictionSchema/res/drawable-hdpi/ic_launcher.png b/samples/browseable/AppRestrictionSchema/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 74344d7c3..000000000
--- a/samples/browseable/AppRestrictionSchema/res/drawable-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AppRestrictionSchema/res/drawable-mdpi/ic_launcher.png b/samples/browseable/AppRestrictionSchema/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index a01dbd77b..000000000
--- a/samples/browseable/AppRestrictionSchema/res/drawable-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AppRestrictionSchema/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/AppRestrictionSchema/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 19bb139de..000000000
--- a/samples/browseable/AppRestrictionSchema/res/drawable-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AppRestrictionSchema/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/AppRestrictionSchema/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 9922ae6e0..000000000
--- a/samples/browseable/AppRestrictionSchema/res/drawable-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AppRestrictionSchema/res/layout/fragment_app_restriction_schema.xml b/samples/browseable/AppRestrictionSchema/res/layout/fragment_app_restriction_schema.xml
index 01bda925d..de43e1a36 100644
--- a/samples/browseable/AppRestrictionSchema/res/layout/fragment_app_restriction_schema.xml
+++ b/samples/browseable/AppRestrictionSchema/res/layout/fragment_app_restriction_schema.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +16,9 @@ limitations under the License.
<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">
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
@@ -32,50 +31,50 @@ limitations under the License.
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
- tools:text="@string/explanation_can_say_hello_true"/>
+ 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_marginBottom="@dimen/margin_medium"
android:layout_marginStart="@dimen/margin_medium"
- android:text="@string/action_can_say_hello"/>
-
- <include layout="@layout/separator"/>
+ android:text="@string/action_can_say_hello" />
<TextView
android:id="@+id/your_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/margin_medium"
+ android:layout_marginTop="@dimen/margin_medium"
android:textAppearance="?android:attr/textAppearanceMedium"
- tools:text="@string/your_number"/>
-
- <include layout="@layout/separator"/>
+ tools:text="@string/your_number" />
<TextView
android:id="@+id/your_rank"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/margin_medium"
+ android:layout_marginTop="@dimen/margin_medium"
android:textAppearance="?android:attr/textAppearanceMedium"
- tools:text="@string/your_rank"/>
-
- <include layout="@layout/separator" android:id="@+id/bundle_separator"/>
+ tools:text="@string/your_rank" />
<TextView
android:id="@+id/approvals_you_have"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/margin_medium"
+ android:layout_marginTop="@dimen/margin_medium"
android:textAppearance="?android:attr/textAppearanceMedium"
- tools:text="@string/approvals_you_have"/>
-
- <include layout="@layout/separator" android:id="@+id/bundle_array_separator" />
+ tools:text="@string/approvals_you_have" />
<TextView
android:id="@+id/your_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/margin_medium"
android:textAppearance="?android:attr/textAppearanceMedium"
- tools:text="@string/your_items"/>
+ tools:text="@string/your_items" />
</LinearLayout>
diff --git a/samples/browseable/AppRestrictionSchema/res/layout/separator.xml b/samples/browseable/AppRestrictionSchema/res/layout/separator.xml
deleted file mode 100644
index 6927d801c..000000000
--- a/samples/browseable/AppRestrictionSchema/res/layout/separator.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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/samples/browseable/AppRestrictionSchema/res/mipmap-hdpi/ic_launcher.png b/samples/browseable/AppRestrictionSchema/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..419e62861
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionSchema/res/mipmap-mdpi/ic_launcher.png b/samples/browseable/AppRestrictionSchema/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..16ec1ce20
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionSchema/res/mipmap-xhdpi/ic_launcher.png b/samples/browseable/AppRestrictionSchema/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..4a1929ee2
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionSchema/res/mipmap-xxhdpi/ic_launcher.png b/samples/browseable/AppRestrictionSchema/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..b35996420
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionSchema/res/mipmap-xxxhdpi/ic_launcher.png b/samples/browseable/AppRestrictionSchema/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..0c3cf753a
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionSchema/src/com.example.android.apprestrictionschema/AppRestrictionSchemaFragment.java b/samples/browseable/AppRestrictionSchema/src/com.example.android.apprestrictionschema/AppRestrictionSchemaFragment.java
index f15bd9d41..3f4cea012 100644
--- a/samples/browseable/AppRestrictionSchema/src/com.example.android.apprestrictionschema/AppRestrictionSchemaFragment.java
+++ b/samples/browseable/AppRestrictionSchema/src/com.example.android.apprestrictionschema/AppRestrictionSchemaFragment.java
@@ -81,17 +81,11 @@ public class AppRestrictionSchemaFragment extends Fragment implements View.OnCli
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);
- View bundleSeparator = view.findViewById(R.id.bundle_separator);
- View bundleArraySeparator = view.findViewById(R.id.bundle_array_separator);
mTextItems = (TextView) view.findViewById(R.id.your_items);
mButtonSayHello.setOnClickListener(this);
if (BUNDLE_SUPPORTED) {
- bundleSeparator.setVisibility(View.VISIBLE);
- bundleArraySeparator.setVisibility(View.VISIBLE);
mTextItems.setVisibility(View.VISIBLE);
} else {
- bundleSeparator.setVisibility(View.GONE);
- bundleArraySeparator.setVisibility(View.GONE);
mTextItems.setVisibility(View.GONE);
}
}
diff --git a/samples/browseable/AppRestrictions/AndroidManifest.xml b/samples/browseable/AppRestrictions/AndroidManifest.xml
index ddac9cfd1..5c0ca6489 100644
--- a/samples/browseable/AppRestrictions/AndroidManifest.xml
+++ b/samples/browseable/AppRestrictions/AndroidManifest.xml
@@ -18,6 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
package="com.example.android.apprestrictions"
android:versionCode="1"
android:versionName="1.0">
@@ -25,7 +26,9 @@
<!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:label="@string/app_name"
- android:icon="@drawable/ic_launcher">
+ android:icon="@mipmap/ic_launcher"
+ android:allowBackup="true"
+ tools:ignore="GoogleAppIndexingWarning">
<activity android:name="MainActivity"
android:label="@string/app_name" >
diff --git a/samples/browseable/AppRestrictions/res/drawable-hdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/drawable-hdpi/ic_launcher.png
deleted file mode 100755
index f36c473a1..000000000
--- a/samples/browseable/AppRestrictions/res/drawable-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AppRestrictions/res/drawable-mdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/drawable-mdpi/ic_launcher.png
deleted file mode 100755
index 5ab2e0d33..000000000
--- a/samples/browseable/AppRestrictions/res/drawable-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AppRestrictions/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100755
index 76228388e..000000000
--- a/samples/browseable/AppRestrictions/res/drawable-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AppRestrictions/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100755
index 7f55feff2..000000000
--- a/samples/browseable/AppRestrictions/res/drawable-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AppRestrictions/res/layout/main.xml b/samples/browseable/AppRestrictions/res/layout/main.xml
index 55e2c8eb4..5228754f7 100644
--- a/samples/browseable/AppRestrictions/res/layout/main.xml
+++ b/samples/browseable/AppRestrictions/res/layout/main.xml
@@ -18,7 +18,7 @@ limitations under the License.
android:layout_height="match_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:layout_margin="20dp">
<TextView android:layout_width="match_parent"
@@ -35,7 +35,7 @@ limitations under the License.
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onCustomClicked"/>
- <TextView android:layout_width="wrap_content"
+ <TextView android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="@string/custom_description"
@@ -63,7 +63,7 @@ limitations under the License.
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="20dp">
+ android:layout_marginStart="20dp">
<TextView android:layout_width="210dp"
android:layout_height="wrap_content"
android:textSize="18sp"
@@ -80,7 +80,7 @@ limitations under the License.
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="20dp">
+ android:layout_marginStart="20dp">
<TextView android:layout_width="210dp"
android:layout_height="wrap_content"
android:textSize="18sp"
@@ -97,7 +97,7 @@ limitations under the License.
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="20dp">
+ android:layout_marginStart="20dp">
<TextView android:layout_width="210dp"
android:layout_height="wrap_content"
android:textSize="18sp"
diff --git a/samples/browseable/AppRestrictions/res/mipmap-hdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..f411ebbfd
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictions/res/mipmap-mdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..4489c8dd2
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictions/res/mipmap-xhdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..07473b8e1
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictions/res/mipmap-xxhdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..71d7bb727
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictions/res/mipmap-xxxhdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..8f9e6cc81
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsFragment.java b/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsFragment.java
index b04dfd1f7..516eb510f 100644
--- a/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsFragment.java
+++ b/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsFragment.java
@@ -29,6 +29,7 @@ import android.preference.Preference;
import android.preference.PreferenceFragment;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -123,16 +124,14 @@ public class CustomRestrictionsFragment extends PreferenceFragment
mChoicePref.setValue(entry.getSelectedString());
mChoiceEntry = entry;
} else if (entry.getKey().equals(GetRestrictionsReceiver.KEY_MULTI_SELECT)) {
- HashSet<String> set = new HashSet<String>();
- for (String value : entry.getAllSelectedStrings()) {
- set.add(value);
- }
+ HashSet<String> set = new HashSet<>();
+ Collections.addAll(set, entry.getAllSelectedStrings());
mMultiPref.setValues(set);
mMultiEntry = entry;
}
}
} else {
- mRestrictions = new ArrayList<RestrictionEntry>();
+ mRestrictions = new ArrayList<>();
// Initializes the boolean restriction entry and updates its corresponding shared
// preference value.
@@ -155,13 +154,11 @@ public class CustomRestrictionsFragment extends PreferenceFragment
GetRestrictionsReceiver.KEY_MULTI_SELECT));
mMultiEntry.setType(RestrictionEntry.TYPE_MULTI_SELECT);
if (mMultiEntry.getAllSelectedStrings() != null) {
- HashSet<String> set = new HashSet<String>();
+ HashSet<String> set = new HashSet<>();
final String[] values = mRestrictionsBundle.getStringArray(
GetRestrictionsReceiver.KEY_MULTI_SELECT);
if (values != null) {
- for (String value : values) {
- set.add(value);
- }
+ Collections.addAll(set, values);
}
mMultiPref.setValues(set);
}
@@ -173,7 +170,7 @@ public class CustomRestrictionsFragment extends PreferenceFragment
// activity finishes.
Intent intent = new Intent(getActivity().getIntent());
intent.putParcelableArrayListExtra(Intent.EXTRA_RESTRICTIONS_LIST,
- new ArrayList<RestrictionEntry>(mRestrictions));
+ new ArrayList<>(mRestrictions));
getActivity().setResult(Activity.RESULT_OK, intent);
}
@@ -183,9 +180,12 @@ public class CustomRestrictionsFragment extends PreferenceFragment
mBooleanEntry.setSelectedState((Boolean) newValue);
} else if (preference == mChoicePref) {
mChoiceEntry.setSelectedString((String) newValue);
- } else if (preference == mMultiPref) {
- String[] selectedStrings = new String[((Set<String>)newValue).size()];
+ } else if (preference == mMultiPref && newValue instanceof Set) {
+ // newValue is a Set<String>, skip the lint warning.
+ //noinspection unchecked
+ String[] selectedStrings = new String[((Set<String>) newValue).size()];
int i = 0;
+ //noinspection unchecked
for (String value : (Set<String>) newValue) {
selectedStrings[i++] = value;
}
@@ -195,7 +195,7 @@ public class CustomRestrictionsFragment extends PreferenceFragment
// Saves all the app restriction configuration changes from the custom activity.
Intent intent = new Intent(getActivity().getIntent());
intent.putParcelableArrayListExtra(Intent.EXTRA_RESTRICTIONS_LIST,
- new ArrayList<RestrictionEntry>(mRestrictions));
+ new ArrayList<>(mRestrictions));
getActivity().setResult(Activity.RESULT_OK, intent);
return true;
}
diff --git a/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/GetRestrictionsReceiver.java b/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/GetRestrictionsReceiver.java
index bb5a28391..a17a6c118 100644
--- a/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/GetRestrictionsReceiver.java
+++ b/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/GetRestrictionsReceiver.java
@@ -88,7 +88,7 @@ public class GetRestrictionsReceiver extends BroadcastReceiver {
// Demonstrates the creation of standard app restriction types: boolean, single choice, and
// multi-select.
private ArrayList<RestrictionEntry> initRestrictions(Context context) {
- ArrayList<RestrictionEntry> newRestrictions = new ArrayList<RestrictionEntry>();
+ ArrayList<RestrictionEntry> newRestrictions = new ArrayList<>();
Resources res = context.getResources();
RestrictionEntry reBoolean = new RestrictionEntry(KEY_BOOLEAN, false);
diff --git a/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/MainActivity.java b/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/MainActivity.java
index 57c443906..1e76fbda8 100644
--- a/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/MainActivity.java
+++ b/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/MainActivity.java
@@ -120,12 +120,10 @@ public class MainActivity extends Activity {
*
* This flag is used by {@code GetRestrictionsReceiver} to determine if a custom app
* restriction activity should be used.
- *
- * @param view
*/
public void onCustomClicked(View view) {
final SharedPreferences.Editor editor =
PreferenceManager.getDefaultSharedPreferences(this).edit();
- editor.putBoolean(CUSTOM_CONFIG_KEY, mCustomConfig.isChecked()).commit();
+ editor.putBoolean(CUSTOM_CONFIG_KEY, mCustomConfig.isChecked()).apply();
}
}
diff --git a/samples/browseable/AppShortcuts/AndroidManifest.xml b/samples/browseable/AppShortcuts/AndroidManifest.xml
index 9dfc7a3a8..183bc84d9 100644
--- a/samples/browseable/AppShortcuts/AndroidManifest.xml
+++ b/samples/browseable/AppShortcuts/AndroidManifest.xml
@@ -23,7 +23,8 @@
<application
android:label="@string/app_name"
- android:icon="@drawable/app"
+ android:icon="@mipmap/ic_launcher"
+ android:roundIcon="@mipmap/ic_launcher_round"
android:resizeableActivity="true">
<activity android:name="com.example.android.appshortcuts.Main">
diff --git a/samples/browseable/AppShortcuts/res/drawable-nodpi/app.png b/samples/browseable/AppShortcuts/res/drawable-nodpi/app.png
deleted file mode 100644
index 39ca2f973..000000000
--- a/samples/browseable/AppShortcuts/res/drawable-nodpi/app.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/AppShortcuts/res/mipmap-hdpi/ic_launcher.png b/samples/browseable/AppShortcuts/res/mipmap-hdpi/ic_launcher.png
new file mode 100755
index 000000000..cb86b9743
--- /dev/null
+++ b/samples/browseable/AppShortcuts/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppShortcuts/res/mipmap-hdpi/ic_launcher_round.png b/samples/browseable/AppShortcuts/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 000000000..7502f5d60
--- /dev/null
+++ b/samples/browseable/AppShortcuts/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/AppShortcuts/res/mipmap-mdpi/ic_launcher.png b/samples/browseable/AppShortcuts/res/mipmap-mdpi/ic_launcher.png
new file mode 100755
index 000000000..bfeec7a38
--- /dev/null
+++ b/samples/browseable/AppShortcuts/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppShortcuts/res/mipmap-mdpi/ic_launcher_round.png b/samples/browseable/AppShortcuts/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 000000000..13ca6d75f
--- /dev/null
+++ b/samples/browseable/AppShortcuts/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/AppShortcuts/res/mipmap-xhdpi/ic_launcher.png b/samples/browseable/AppShortcuts/res/mipmap-xhdpi/ic_launcher.png
new file mode 100755
index 000000000..358442e05
--- /dev/null
+++ b/samples/browseable/AppShortcuts/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppShortcuts/res/mipmap-xhdpi/ic_launcher_round.png b/samples/browseable/AppShortcuts/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..ff93f4d14
--- /dev/null
+++ b/samples/browseable/AppShortcuts/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/AppShortcuts/res/mipmap-xxhdpi/ic_launcher.png b/samples/browseable/AppShortcuts/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100755
index 000000000..c99a1a000
--- /dev/null
+++ b/samples/browseable/AppShortcuts/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppShortcuts/res/mipmap-xxhdpi/ic_launcher_round.png b/samples/browseable/AppShortcuts/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..8b642db83
--- /dev/null
+++ b/samples/browseable/AppShortcuts/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/AppShortcuts/res/mipmap-xxxhdpi/ic_launcher.png b/samples/browseable/AppShortcuts/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100755
index 000000000..3bcda818b
--- /dev/null
+++ b/samples/browseable/AppShortcuts/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppShortcuts/res/mipmap-xxxhdpi/ic_launcher_round.png b/samples/browseable/AppShortcuts/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..a49362e32
--- /dev/null
+++ b/samples/browseable/AppShortcuts/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/AsymmetricFingerprintDialog/AndroidManifest.xml b/samples/browseable/AsymmetricFingerprintDialog/AndroidManifest.xml
index d1cf9f870..4dce26600 100644
--- a/samples/browseable/AsymmetricFingerprintDialog/AndroidManifest.xml
+++ b/samples/browseable/AsymmetricFingerprintDialog/AndroidManifest.xml
@@ -14,25 +14,29 @@
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.asymmetricfingerprintdialog"
- android:versionCode="1"
- android:versionName="1.0">
+<manifest package="com.example.android.asymmetricfingerprintdialog"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:versionCode="1"
+ android:versionName="1.0">
- <uses-permission android:name="android.permission.USE_FINGERPRINT"/>
+ <uses-permission android:name="android.permission.USE_FINGERPRINT" />
<application
- android:name=".InjectedApplication"
- android:allowBackup="true"
- android:label="@string/app_name"
- android:icon="@mipmap/ic_launcher"
- android:theme="@style/AppTheme">
+ android:name=".InjectedApplication"
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme"
+ tools:ignore="GoogleAppIndexingWarning">
- <activity android:name=".MainActivity"
- android:label="@string/app_name">
+ <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"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
diff --git a/samples/browseable/AsymmetricFingerprintDialog/res/layout/activity_main.xml b/samples/browseable/AsymmetricFingerprintDialog/res/layout/activity_main.xml
index 8f30557b9..16b29bd89 100644
--- a/samples/browseable/AsymmetricFingerprintDialog/res/layout/activity_main.xml
+++ b/samples/browseable/AsymmetricFingerprintDialog/res/layout/activity_main.xml
@@ -31,7 +31,8 @@
android:layout_marginBottom="32dp"
android:layout_gravity="center_horizontal"
android:scaleType="fitCenter"
- android:src="@drawable/android_robot"/>
+ android:src="@drawable/android_robot"
+ android:contentDescription="@string/description_bugdroid_icon" />
<LinearLayout
android:layout_width="match_parent"
@@ -77,8 +78,7 @@
android:layout_gravity="end"
android:textColor="?android:attr/textColorPrimaryInverse"
android:text="@string/purchase"
- android:id="@+id/purchase_button"
- android:layout_alignParentEnd="true"/>
+ android:id="@+id/purchase_button"/>
<TextView
android:id="@+id/confirmation_message"
diff --git a/samples/browseable/AsymmetricFingerprintDialog/res/layout/fingerprint_dialog_content.xml b/samples/browseable/AsymmetricFingerprintDialog/res/layout/fingerprint_dialog_content.xml
index 3929ebae6..5bb65b2ac 100644
--- a/samples/browseable/AsymmetricFingerprintDialog/res/layout/fingerprint_dialog_content.xml
+++ b/samples/browseable/AsymmetricFingerprintDialog/res/layout/fingerprint_dialog_content.xml
@@ -41,7 +41,8 @@
android:layout_alignParentStart="true"
android:layout_below="@+id/fingerprint_description"
android:layout_marginTop="20dp"
- android:src="@drawable/ic_fp_40px" />
+ android:src="@drawable/ic_fp_40px"
+ android:contentDescription="@string/description_fingerprint_icon"/>
<TextView
android:id="@+id/fingerprint_status"
diff --git a/samples/browseable/AsymmetricFingerprintDialog/res/menu/menu_main.xml b/samples/browseable/AsymmetricFingerprintDialog/res/menu/menu_main.xml
index 73f5e89a0..15969703a 100644
--- a/samples/browseable/AsymmetricFingerprintDialog/res/menu/menu_main.xml
+++ b/samples/browseable/AsymmetricFingerprintDialog/res/menu/menu_main.xml
@@ -15,7 +15,12 @@
~ limitations under the License
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
- <item android:id="@+id/action_settings" android:title="@string/action_settings"
- android:orderInCategory="100" android:showAsAction="never" />
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:context=".MainActivity">
+ <item
+ android:id="@+id/action_settings"
+ android:orderInCategory="100"
+ android:title="@string/action_settings"
+ app:showAsAction="never" />
</menu>
diff --git a/samples/browseable/AsymmetricFingerprintDialog/res/values/strings.xml b/samples/browseable/AsymmetricFingerprintDialog/res/values/strings.xml
index f44c06d68..86b8d422d 100644
--- a/samples/browseable/AsymmetricFingerprintDialog/res/values/strings.xml
+++ b/samples/browseable/AsymmetricFingerprintDialog/res/values/strings.xml
@@ -19,7 +19,7 @@
<string name="cancel">Cancel</string>
<string name="use_password">Use password</string>
<string name="sign_in">Sign in</string>
- <string name="ok">Ok</string>
+ <string name="ok">OK</string>
<string name="password">Password</string>
<string name="fingerprint_description">Confirm fingerprint to continue</string>
<string name="fingerprint_hint">Touch sensor</string>
@@ -36,4 +36,6 @@
<string name="use_fingerprint_in_future">Use fingerprint in the future</string>
<string name="use_fingerprint_to_authenticate_title">Use fingerprint to authenticate</string>
<string name="use_fingerprint_to_authenticate_key" >use_fingerprint_to_authenticate_key</string>
+ <string name="description_bugdroid_icon">Android bugdroid image</string>
+ <string name="description_fingerprint_icon">Fingerprint icon</string>
</resources>
diff --git a/samples/browseable/AsymmetricFingerprintDialog/src/com.example.android.asymmetricfingerprintdialog/FingerprintAuthenticationDialogFragment.java b/samples/browseable/AsymmetricFingerprintDialog/src/com.example.android.asymmetricfingerprintdialog/FingerprintAuthenticationDialogFragment.java
index a56556f13..fbe8ec9c3 100644
--- a/samples/browseable/AsymmetricFingerprintDialog/src/com.example.android.asymmetricfingerprintdialog/FingerprintAuthenticationDialogFragment.java
+++ b/samples/browseable/AsymmetricFingerprintDialog/src/com.example.android.asymmetricfingerprintdialog/FingerprintAuthenticationDialogFragment.java
@@ -19,8 +19,8 @@ package com.example.android.asymmetricfingerprintdialog;
import com.example.android.asymmetricfingerprintdialog.server.StoreBackend;
import com.example.android.asymmetricfingerprintdialog.server.Transaction;
-import android.app.Activity;
import android.app.DialogFragment;
+import android.content.Context;
import android.content.SharedPreferences;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
@@ -158,9 +158,9 @@ public class FingerprintAuthenticationDialogFragment extends DialogFragment
}
@Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- mActivity = (MainActivity) activity;
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mActivity = (MainActivity) getActivity();
}
/**
diff --git a/samples/browseable/AsymmetricFingerprintDialog/src/com.example.android.asymmetricfingerprintdialog/FingerprintUiHelper.java b/samples/browseable/AsymmetricFingerprintDialog/src/com.example.android.asymmetricfingerprintdialog/FingerprintUiHelper.java
index f65481161..dee427099 100644
--- a/samples/browseable/AsymmetricFingerprintDialog/src/com.example.android.asymmetricfingerprintdialog/FingerprintUiHelper.java
+++ b/samples/browseable/AsymmetricFingerprintDialog/src/com.example.android.asymmetricfingerprintdialog/FingerprintUiHelper.java
@@ -27,7 +27,11 @@ import javax.inject.Inject;
/**
* Small helper class to manage text/icon around fingerprint authentication UI.
+ * This class assumes that the {@link android.Manifest.permission#USE_FINGERPRINT}
+ * permission has already been granted. (As of API 23 this permission is normal instead of dangerous
+ * and is granted at install time.)
*/
+@SuppressWarnings("MissingPermission")
public class FingerprintUiHelper extends FingerprintManager.AuthenticationCallback {
@VisibleForTesting static final long ERROR_TIMEOUT_MILLIS = 1600;
diff --git a/samples/browseable/BasicAndroidKeyStore/AndroidManifest.xml b/samples/browseable/BasicAndroidKeyStore/AndroidManifest.xml
index 1c3b255fa..1f8a43198 100644
--- a/samples/browseable/BasicAndroidKeyStore/AndroidManifest.xml
+++ b/samples/browseable/BasicAndroidKeyStore/AndroidManifest.xml
@@ -26,7 +26,7 @@
<application android:allowBackup="true"
android:label="@string/app_name"
- android:icon="@drawable/ic_launcher"
+ android:icon="@mipmap/ic_launcher"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
diff --git a/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index b1efaf4b2..000000000
--- a/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/BasicAndroidKeyStore/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index f5f9244f2..000000000
--- a/samples/browseable/BasicAndroidKeyStore/res/drawable-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/BasicAndroidKeyStore/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 5d07b3f06..000000000
--- a/samples/browseable/BasicAndroidKeyStore/res/drawable-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/BasicAndroidKeyStore/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 6ef21e1f4..000000000
--- a/samples/browseable/BasicAndroidKeyStore/res/drawable-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/browseable/BasicAndroidKeyStore/res/mipmap-hdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..c57b83ab7
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicAndroidKeyStore/res/mipmap-mdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..c43fc24ac
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicAndroidKeyStore/res/mipmap-xhdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..4255f237f
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicAndroidKeyStore/res/mipmap-xxhdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..f6ca8a92b
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicAndroidKeyStore/res/mipmap-xxxhdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..0f623f6f4
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/BasicAndroidKeyStoreFragment.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/BasicAndroidKeyStoreFragment.java
index e6244bfb6..3616e88e4 100644
--- a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/BasicAndroidKeyStoreFragment.java
+++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/BasicAndroidKeyStoreFragment.java
@@ -16,15 +16,18 @@
package com.example.android.basicandroidkeystore;
+import com.example.android.common.logger.Log;
+
import android.content.Context;
+import android.os.Build;
import android.os.Bundle;
import android.security.KeyPairGeneratorSpec;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
import android.support.v4.app.Fragment;
import android.util.Base64;
import android.view.MenuItem;
-import com.example.android.common.logger.Log;
-
import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
@@ -39,6 +42,7 @@ import java.security.Signature;
import java.security.SignatureException;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;
+import java.security.spec.AlgorithmParameterSpec;
import java.util.Calendar;
import java.util.GregorianCalendar;
@@ -46,7 +50,7 @@ import javax.security.auth.x500.X500Principal;
public class BasicAndroidKeyStoreFragment extends Fragment {
- public static final String TAG = "BasicAndroidKeyStoreFragment";
+ public static final String TAG = "KeyStoreFragment";
// BEGIN_INCLUDE(values)
@@ -159,36 +163,54 @@ public class BasicAndroidKeyStoreFragment extends Fragment {
end.add(Calendar.YEAR, 1);
//END_INCLUDE(create_valid_dates)
-
- // BEGIN_INCLUDE(create_spec)
- // The KeyPairGeneratorSpec object is how parameters for your key pair are passed
- // to the KeyPairGenerator. For a fun home game, count how many classes in this sample
- // start with the phrase "KeyPair".
- KeyPairGeneratorSpec spec =
- new KeyPairGeneratorSpec.Builder(context)
- // You'll use the alias later to retrieve the key. It's a key for the key!
- .setAlias(mAlias)
- // The subject used for the self-signed certificate of the generated pair
- .setSubject(new X500Principal("CN=" + mAlias))
- // The serial number used for the self-signed certificate of the
- // generated pair.
- .setSerialNumber(BigInteger.valueOf(1337))
- // Date range of validity for the generated pair.
- .setStartDate(start.getTime())
- .setEndDate(end.getTime())
- .build();
- // END_INCLUDE(create_spec)
-
// BEGIN_INCLUDE(create_keypair)
// Initialize a KeyPair generator using the the intended algorithm (in this example, RSA
// and the KeyStore. This example uses the AndroidKeyStore.
KeyPairGenerator kpGenerator = KeyPairGenerator
.getInstance(SecurityConstants.TYPE_RSA,
SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
+ // END_INCLUDE(create_keypair)
+
+ // BEGIN_INCLUDE(create_spec)
+ // The KeyPairGeneratorSpec object is how parameters for your key pair are passed
+ // to the KeyPairGenerator.
+ AlgorithmParameterSpec spec;
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ // Below Android M, use the KeyPairGeneratorSpec.Builder.
+
+ spec = new KeyPairGeneratorSpec.Builder(context)
+ // You'll use the alias later to retrieve the key. It's a key for the key!
+ .setAlias(mAlias)
+ // The subject used for the self-signed certificate of the generated pair
+ .setSubject(new X500Principal("CN=" + mAlias))
+ // The serial number used for the self-signed certificate of the
+ // generated pair.
+ .setSerialNumber(BigInteger.valueOf(1337))
+ // Date range of validity for the generated pair.
+ .setStartDate(start.getTime())
+ .setEndDate(end.getTime())
+ .build();
+
+
+ } else {
+ // On Android M or above, use the KeyGenparameterSpec.Builder and specify permitted
+ // properties and restrictions of the key.
+ spec = new KeyGenParameterSpec.Builder(mAlias, KeyProperties.PURPOSE_SIGN)
+ .setCertificateSubject(new X500Principal("CN=" + mAlias))
+ .setDigests(KeyProperties.DIGEST_SHA256)
+ .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
+ .setCertificateSerialNumber(BigInteger.valueOf(1337))
+ .setCertificateNotBefore(start.getTime())
+ .setCertificateNotAfter(end.getTime())
+ .build();
+ }
+
kpGenerator.initialize(spec);
+
KeyPair kp = kpGenerator.generateKeyPair();
+ // END_INCLUDE(create_spec)
Log.d(TAG, "Public Key is: " + kp.getPublic().toString());
- // END_INCLUDE(create_keypair)
}
/**
diff --git a/samples/browseable/BasicGestureDetect/res/menu/main.xml b/samples/browseable/BasicGestureDetect/res/menu/main.xml
index 2c3515dd4..498f2c60e 100644
--- a/samples/browseable/BasicGestureDetect/res/menu/main.xml
+++ b/samples/browseable/BasicGestureDetect/res/menu/main.xml
@@ -14,8 +14,9 @@
limitations under the License.
-->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/sample_action"
- android:showAsAction="ifRoom|withText"
+ app:showAsAction="ifRoom|withText"
android:title="@string/sample_action" />
</menu>
diff --git a/samples/browseable/BasicImmersiveMode/res/menu/main.xml b/samples/browseable/BasicImmersiveMode/res/menu/main.xml
index 2c3515dd4..498f2c60e 100644
--- a/samples/browseable/BasicImmersiveMode/res/menu/main.xml
+++ b/samples/browseable/BasicImmersiveMode/res/menu/main.xml
@@ -14,8 +14,9 @@
limitations under the License.
-->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/sample_action"
- android:showAsAction="ifRoom|withText"
+ app:showAsAction="ifRoom|withText"
android:title="@string/sample_action" />
</menu>
diff --git a/samples/browseable/BluetoothChat/src/com.example.android.bluetoothchat/BluetoothChatFragment.java b/samples/browseable/BluetoothChat/src/com.example.android.bluetoothchat/BluetoothChatFragment.java
index 8ee906246..b77ef558e 100644
--- a/samples/browseable/BluetoothChat/src/com.example.android.bluetoothchat/BluetoothChatFragment.java
+++ b/samples/browseable/BluetoothChat/src/com.example.android.bluetoothchat/BluetoothChatFragment.java
@@ -188,7 +188,7 @@ public class BluetoothChatFragment extends Fragment {
}
/**
- * Makes this device discoverable.
+ * Makes this device discoverable for 300 seconds (5 minutes).
*/
private void ensureDiscoverable() {
if (mBluetoothAdapter.getScanMode() !=
@@ -355,7 +355,7 @@ public class BluetoothChatFragment extends Fragment {
}
/**
- * Establish connection with other divice
+ * Establish connection with other device
*
* @param data An {@link Intent} with {@link DeviceListActivity#EXTRA_DEVICE_ADDRESS} extra.
* @param secure Socket Security type - Secure (true) , Insecure (false)
diff --git a/samples/browseable/BluetoothChat/src/com.example.android.bluetoothchat/BluetoothChatService.java b/samples/browseable/BluetoothChat/src/com.example.android.bluetoothchat/BluetoothChatService.java
index a1e7cc016..ad4a6d1bb 100644
--- a/samples/browseable/BluetoothChat/src/com.example.android.bluetoothchat/BluetoothChatService.java
+++ b/samples/browseable/BluetoothChat/src/com.example.android.bluetoothchat/BluetoothChatService.java
@@ -60,6 +60,7 @@ public class BluetoothChatService {
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
+ private int mNewState;
// Constants that indicate the current connection state
public static final int STATE_NONE = 0; // we're doing nothing
@@ -76,20 +77,20 @@ public class BluetoothChatService {
public BluetoothChatService(Context context, Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
+ mNewState = mState;
mHandler = handler;
}
/**
- * Set the current state of the chat connection
- *
- * @param state An integer defining the current connection state
+ * Update UI title according to the current state of the chat connection
*/
- private synchronized void setState(int state) {
- Log.d(TAG, "setState() " + mState + " -> " + state);
- mState = state;
+ private synchronized void updateUserInterfaceTitle() {
+ mState = getState();
+ Log.d(TAG, "updateUserInterfaceTitle() " + mNewState + " -> " + mState);
+ mNewState = mState;
// Give the new state to the Handler so the UI Activity can update
- mHandler.obtainMessage(Constants.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
+ mHandler.obtainMessage(Constants.MESSAGE_STATE_CHANGE, mNewState, -1).sendToTarget();
}
/**
@@ -118,8 +119,6 @@ public class BluetoothChatService {
mConnectedThread = null;
}
- setState(STATE_LISTEN);
-
// Start the thread to listen on a BluetoothServerSocket
if (mSecureAcceptThread == null) {
mSecureAcceptThread = new AcceptThread(true);
@@ -129,6 +128,8 @@ public class BluetoothChatService {
mInsecureAcceptThread = new AcceptThread(false);
mInsecureAcceptThread.start();
}
+ // Update UI title
+ updateUserInterfaceTitle();
}
/**
@@ -157,7 +158,8 @@ public class BluetoothChatService {
// Start the thread to connect with the given device
mConnectThread = new ConnectThread(device, secure);
mConnectThread.start();
- setState(STATE_CONNECTING);
+ // Update UI title
+ updateUserInterfaceTitle();
}
/**
@@ -202,8 +204,8 @@ public class BluetoothChatService {
bundle.putString(Constants.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
-
- setState(STATE_CONNECTED);
+ // Update UI title
+ updateUserInterfaceTitle();
}
/**
@@ -231,7 +233,9 @@ public class BluetoothChatService {
mInsecureAcceptThread.cancel();
mInsecureAcceptThread = null;
}
- setState(STATE_NONE);
+ mState = STATE_NONE;
+ // Update UI title
+ updateUserInterfaceTitle();
}
/**
@@ -263,6 +267,10 @@ public class BluetoothChatService {
msg.setData(bundle);
mHandler.sendMessage(msg);
+ mState = STATE_NONE;
+ // Update UI title
+ updateUserInterfaceTitle();
+
// Start the service over to restart listening mode
BluetoothChatService.this.start();
}
@@ -278,6 +286,10 @@ public class BluetoothChatService {
msg.setData(bundle);
mHandler.sendMessage(msg);
+ mState = STATE_NONE;
+ // Update UI title
+ updateUserInterfaceTitle();
+
// Start the service over to restart listening mode
BluetoothChatService.this.start();
}
@@ -309,6 +321,7 @@ public class BluetoothChatService {
Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed", e);
}
mmServerSocket = tmp;
+ mState = STATE_LISTEN;
}
public void run() {
@@ -396,6 +409,7 @@ public class BluetoothChatService {
Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
}
mmSocket = tmp;
+ mState = STATE_CONNECTING;
}
public void run() {
@@ -465,6 +479,7 @@ public class BluetoothChatService {
mmInStream = tmpIn;
mmOutStream = tmpOut;
+ mState = STATE_CONNECTED;
}
public void run() {
@@ -484,8 +499,6 @@ public class BluetoothChatService {
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
- // Start the service over to restart listening mode
- BluetoothChatService.this.start();
break;
}
}
diff --git a/samples/browseable/CardView/_index.jd b/samples/browseable/CardView/_index.jd
index 3d8c9e072..c4dd1db16 100644
--- a/samples/browseable/CardView/_index.jd
+++ b/samples/browseable/CardView/_index.jd
@@ -5,7 +5,7 @@ sample.group=UI
<p>
- This sample demonstrates how to use CardView introduced in the support library for the
- Android L preview.
+ This sample demonstrates how to use CardView introduced in the support library in
+ Android 5.0.
</p>
diff --git a/samples/browseable/CardView/res/values/base-strings.xml b/samples/browseable/CardView/res/values/base-strings.xml
index 12863226d..4db434965 100644
--- a/samples/browseable/CardView/res/values/base-strings.xml
+++ b/samples/browseable/CardView/res/values/base-strings.xml
@@ -21,8 +21,8 @@
<![CDATA[
- This sample demonstrates how to use CardView introduced in the support library for the
- Android L preview.
+ This sample demonstrates how to use CardView introduced in the support library in
+ Android 5.0.
]]>
diff --git a/samples/browseable/CommitContentSampleApp/AndroidManifest.xml b/samples/browseable/CommitContentSampleApp/AndroidManifest.xml
index 16c93b117..a7335943b 100644
--- a/samples/browseable/CommitContentSampleApp/AndroidManifest.xml
+++ b/samples/browseable/CommitContentSampleApp/AndroidManifest.xml
@@ -4,6 +4,7 @@
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
+ android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
diff --git a/samples/browseable/CommitContentSampleApp/res/mipmap-hdpi/ic_launcher.png b/samples/browseable/CommitContentSampleApp/res/mipmap-hdpi/ic_launcher.png
index cde69bccc..e8a0aafc2 100644..100755
--- a/samples/browseable/CommitContentSampleApp/res/mipmap-hdpi/ic_launcher.png
+++ b/samples/browseable/CommitContentSampleApp/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleApp/res/mipmap-hdpi/ic_launcher_round.png b/samples/browseable/CommitContentSampleApp/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 000000000..f2618b01e
--- /dev/null
+++ b/samples/browseable/CommitContentSampleApp/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleApp/res/mipmap-mdpi/ic_launcher.png b/samples/browseable/CommitContentSampleApp/res/mipmap-mdpi/ic_launcher.png
index c133a0cbd..f4ac0f7d6 100644..100755
--- a/samples/browseable/CommitContentSampleApp/res/mipmap-mdpi/ic_launcher.png
+++ b/samples/browseable/CommitContentSampleApp/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleApp/res/mipmap-mdpi/ic_launcher_round.png b/samples/browseable/CommitContentSampleApp/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 000000000..68363185b
--- /dev/null
+++ b/samples/browseable/CommitContentSampleApp/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleApp/res/mipmap-xhdpi/ic_launcher.png b/samples/browseable/CommitContentSampleApp/res/mipmap-xhdpi/ic_launcher.png
index bfa42f0e7..74ee41ade 100644..100755
--- a/samples/browseable/CommitContentSampleApp/res/mipmap-xhdpi/ic_launcher.png
+++ b/samples/browseable/CommitContentSampleApp/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleApp/res/mipmap-xhdpi/ic_launcher_round.png b/samples/browseable/CommitContentSampleApp/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..22be9b823
--- /dev/null
+++ b/samples/browseable/CommitContentSampleApp/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleApp/res/mipmap-xxhdpi/ic_launcher.png b/samples/browseable/CommitContentSampleApp/res/mipmap-xxhdpi/ic_launcher.png
index 324e72cdd..c7eaeb6d0 100644..100755
--- a/samples/browseable/CommitContentSampleApp/res/mipmap-xxhdpi/ic_launcher.png
+++ b/samples/browseable/CommitContentSampleApp/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleApp/res/mipmap-xxhdpi/ic_launcher_round.png b/samples/browseable/CommitContentSampleApp/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..d701598e6
--- /dev/null
+++ b/samples/browseable/CommitContentSampleApp/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleApp/res/mipmap-xxxhdpi/ic_launcher.png b/samples/browseable/CommitContentSampleApp/res/mipmap-xxxhdpi/ic_launcher.png
index aee44e138..dd7ed2e2c 100644..100755
--- a/samples/browseable/CommitContentSampleApp/res/mipmap-xxxhdpi/ic_launcher.png
+++ b/samples/browseable/CommitContentSampleApp/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleApp/res/mipmap-xxxhdpi/ic_launcher_round.png b/samples/browseable/CommitContentSampleApp/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..b4b3ca7bc
--- /dev/null
+++ b/samples/browseable/CommitContentSampleApp/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleIME/AndroidManifest.xml b/samples/browseable/CommitContentSampleIME/AndroidManifest.xml
index f9891ffcb..86a7b37bc 100644
--- a/samples/browseable/CommitContentSampleIME/AndroidManifest.xml
+++ b/samples/browseable/CommitContentSampleIME/AndroidManifest.xml
@@ -4,6 +4,7 @@
<application
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
+ android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
diff --git a/samples/browseable/CommitContentSampleIME/res/mipmap-hdpi/ic_launcher.png b/samples/browseable/CommitContentSampleIME/res/mipmap-hdpi/ic_launcher.png
index cde69bccc..e8a0aafc2 100644..100755
--- a/samples/browseable/CommitContentSampleIME/res/mipmap-hdpi/ic_launcher.png
+++ b/samples/browseable/CommitContentSampleIME/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleIME/res/mipmap-hdpi/ic_launcher_round.png b/samples/browseable/CommitContentSampleIME/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 000000000..f2618b01e
--- /dev/null
+++ b/samples/browseable/CommitContentSampleIME/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleIME/res/mipmap-mdpi/ic_launcher.png b/samples/browseable/CommitContentSampleIME/res/mipmap-mdpi/ic_launcher.png
index c133a0cbd..f4ac0f7d6 100644..100755
--- a/samples/browseable/CommitContentSampleIME/res/mipmap-mdpi/ic_launcher.png
+++ b/samples/browseable/CommitContentSampleIME/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleIME/res/mipmap-mdpi/ic_launcher_round.png b/samples/browseable/CommitContentSampleIME/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 000000000..68363185b
--- /dev/null
+++ b/samples/browseable/CommitContentSampleIME/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleIME/res/mipmap-xhdpi/ic_launcher.png b/samples/browseable/CommitContentSampleIME/res/mipmap-xhdpi/ic_launcher.png
index bfa42f0e7..74ee41ade 100644..100755
--- a/samples/browseable/CommitContentSampleIME/res/mipmap-xhdpi/ic_launcher.png
+++ b/samples/browseable/CommitContentSampleIME/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleIME/res/mipmap-xhdpi/ic_launcher_round.png b/samples/browseable/CommitContentSampleIME/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..22be9b823
--- /dev/null
+++ b/samples/browseable/CommitContentSampleIME/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleIME/res/mipmap-xxhdpi/ic_launcher.png b/samples/browseable/CommitContentSampleIME/res/mipmap-xxhdpi/ic_launcher.png
index 324e72cdd..c7eaeb6d0 100644..100755
--- a/samples/browseable/CommitContentSampleIME/res/mipmap-xxhdpi/ic_launcher.png
+++ b/samples/browseable/CommitContentSampleIME/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleIME/res/mipmap-xxhdpi/ic_launcher_round.png b/samples/browseable/CommitContentSampleIME/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..d701598e6
--- /dev/null
+++ b/samples/browseable/CommitContentSampleIME/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleIME/res/mipmap-xxxhdpi/ic_launcher.png b/samples/browseable/CommitContentSampleIME/res/mipmap-xxxhdpi/ic_launcher.png
index aee44e138..dd7ed2e2c 100644..100755
--- a/samples/browseable/CommitContentSampleIME/res/mipmap-xxxhdpi/ic_launcher.png
+++ b/samples/browseable/CommitContentSampleIME/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleIME/res/mipmap-xxxhdpi/ic_launcher_round.png b/samples/browseable/CommitContentSampleIME/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..b4b3ca7bc
--- /dev/null
+++ b/samples/browseable/CommitContentSampleIME/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/browseable/CommitContentSampleIME/src/com.example.android.commitcontent.ime/ImageKeyboard.java b/samples/browseable/CommitContentSampleIME/src/com.example.android.commitcontent.ime/ImageKeyboard.java
index eb5dae7af..920910087 100644
--- a/samples/browseable/CommitContentSampleIME/src/com.example.android.commitcontent.ime/ImageKeyboard.java
+++ b/samples/browseable/CommitContentSampleIME/src/com.example.android.commitcontent.ime/ImageKeyboard.java
@@ -49,7 +49,7 @@ import java.io.OutputStream;
public class ImageKeyboard extends InputMethodService {
private static final String TAG = "ImageKeyboard";
- private static final String AUTHORITY = "com.example.android.supportv13.sampleime.inputcontent";
+ private static final String AUTHORITY = "com.example.android.commitcontent.ime.inputcontent";
private static final String MIME_TYPE_GIF = "image/gif";
private static final String MIME_TYPE_PNG = "image/png";
private static final String MIME_TYPE_WEBP = "image/webp";
diff --git a/samples/browseable/DataLayer/Wearable/AndroidManifest.xml b/samples/browseable/DataLayer/Wearable/AndroidManifest.xml
index 6608bb705..2bc5f4c7d 100644
--- a/samples/browseable/DataLayer/Wearable/AndroidManifest.xml
+++ b/samples/browseable/DataLayer/Wearable/AndroidManifest.xml
@@ -18,7 +18,7 @@
package="com.example.android.wearable.datalayer" >
<uses-sdk android:minSdkVersion="20"
- android:targetSdkVersion="23" />
+ android:targetSdkVersion="25" />
<uses-feature android:name="android.hardware.type.watch" />
@@ -29,6 +29,10 @@
android:theme="@android:style/Theme.DeviceDefault">
<meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="false" />
+
+ <meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
diff --git a/samples/browseable/DirectBoot/src/com.example.android.directboot/SchedulerFragment.java b/samples/browseable/DirectBoot/src/com.example.android.directboot/SchedulerFragment.java
index 0f32c2589..008961f8a 100644
--- a/samples/browseable/DirectBoot/src/com.example.android.directboot/SchedulerFragment.java
+++ b/samples/browseable/DirectBoot/src/com.example.android.directboot/SchedulerFragment.java
@@ -129,7 +129,7 @@ public class SchedulerFragment extends Fragment {
@Override
public void onReceive(Context context, Intent intent) {
- Alarm alarm = intent.getParcelableExtra(AlarmIntentService.ALARM_KEY);
+ Alarm alarm = AlarmUtil.readAlarm(intent.getExtras());
mAlarmAdapter.deleteAlarm(alarm);
}
}
diff --git a/samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/Alarm.java b/samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/Alarm.java
index 82712c6b7..27ca5c453 100644
--- a/samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/Alarm.java
+++ b/samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/Alarm.java
@@ -16,66 +16,44 @@
package com.example.android.directboot.alarms;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.annotation.NonNull;
-
import org.json.JSONException;
import org.json.JSONObject;
+import android.support.annotation.NonNull;
+
import java.util.Calendar;
import java.util.Objects;
/**
* Class represents a single alarm.
*/
-public class Alarm implements Comparable<Alarm>, Parcelable {
+public class Alarm implements Comparable<Alarm> {
public int id;
+
public int month;
+
public int date;
+
/** Integer as a 24-hour format */
public int hour;
- public int minute;
-
- public Alarm() {}
- protected Alarm(Parcel in) {
- id = in.readInt();
- month = in.readInt();
- date = in.readInt();
- hour = in.readInt();
- minute = in.readInt();
- }
-
- public static final Creator<Alarm> CREATOR = new Creator<Alarm>() {
- @Override
- public Alarm createFromParcel(Parcel in) {
- return new Alarm(in);
- }
-
- @Override
- public Alarm[] newArray(int size) {
- return new Alarm[size];
- }
- };
+ public int minute;
- @Override
- public int describeContents() {
- return 0;
+ public Alarm(int id, int month, int date, int hour, int minute) {
+ this.id = id;
+ this.month = month;
+ this.date = date;
+ this.hour = hour;
+ this.minute = minute;
}
- @Override
- public void writeToParcel(Parcel parcel, int i) {
- parcel.writeInt(id);
- parcel.writeInt(month);
- parcel.writeInt(date);
- parcel.writeInt(hour);
- parcel.writeInt(minute);
+ public Alarm() {
}
/**
* Serialize the instance as a JSON String.
+ *
* @return serialized JSON String.
*/
public String toJson() {
diff --git a/samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/AlarmIntentService.java b/samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/AlarmIntentService.java
index 446345cd4..3909482ef 100644
--- a/samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/AlarmIntentService.java
+++ b/samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/AlarmIntentService.java
@@ -34,7 +34,17 @@ public class AlarmIntentService extends IntentService {
public static final String ALARM_WENT_OFF_ACTION = AlarmIntentService.class.getName()
+ ".ALARM_WENT_OFF";
- public static final String ALARM_KEY = "alarm_instance";
+
+
+ public static final String KEY_ALARM_ID = "alarm_id";
+
+ public static final String KEY_ALARM_MONTH = "alarm_month";
+
+ public static final String KEY_ALARM_DATE = "alarm_date";
+
+ public static final String KEY_ALARM_HOUR = "alarm_hour";
+
+ public static final String KEY_ALARM_MINUTE = "alarm_minute";
public AlarmIntentService() {
super(AlarmIntentService.class.getName());
@@ -43,7 +53,7 @@ public class AlarmIntentService extends IntentService {
@Override
protected void onHandleIntent(Intent intent) {
Context context = getApplicationContext();
- Alarm alarm = intent.getParcelableExtra(ALARM_KEY);
+ Alarm alarm = AlarmUtil.readAlarm(intent.getExtras());
NotificationManager notificationManager = context
.getSystemService(NotificationManager.class);
@@ -59,7 +69,7 @@ public class AlarmIntentService extends IntentService {
AlarmStorage alarmStorage = new AlarmStorage(context);
alarmStorage.deleteAlarm(alarm);
Intent wentOffIntent = new Intent(ALARM_WENT_OFF_ACTION);
- wentOffIntent.putExtra(ALARM_KEY, alarm);
+ wentOffIntent.putExtras(AlarmUtil.writeAlarm(alarm));
LocalBroadcastManager.getInstance(context).sendBroadcast(wentOffIntent);
}
}
diff --git a/samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/AlarmUtil.java b/samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/AlarmUtil.java
index b80e8c9d7..29c01c99d 100644
--- a/samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/AlarmUtil.java
+++ b/samples/browseable/DirectBoot/src/com.example.android.directboot/alarms/AlarmUtil.java
@@ -20,6 +20,7 @@ import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.os.Bundle;
import android.util.Log;
import java.util.Calendar;
@@ -45,7 +46,9 @@ public class AlarmUtil {
*/
public void scheduleAlarm(Alarm alarm) {
Intent intent = new Intent(mContext, AlarmIntentService.class);
- intent.putExtra(AlarmIntentService.ALARM_KEY, alarm);
+ Bundle extras = writeAlarm(alarm);
+ intent.putExtras(extras);
+
PendingIntent pendingIntent = PendingIntent
.getService(mContext, alarm.id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar alarmTime = Calendar.getInstance();
@@ -71,7 +74,6 @@ public class AlarmUtil {
*/
public void cancelAlarm(Alarm alarm) {
Intent intent = new Intent(mContext, AlarmIntentService.class);
- intent.putExtra(AlarmIntentService.ALARM_KEY, alarm);
PendingIntent pendingIntent = PendingIntent
.getService(mContext, alarm.id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mAlarmManager.cancel(pendingIntent);
@@ -94,4 +96,25 @@ public class AlarmUtil {
}
return alarmTime;
}
+
+ public static Alarm readAlarm(Bundle extras) {
+ int id = extras.getInt(AlarmIntentService.KEY_ALARM_ID);
+ int month = extras.getInt(AlarmIntentService.KEY_ALARM_MONTH);
+ int date = extras.getInt(AlarmIntentService.KEY_ALARM_DATE);
+ int hour = extras.getInt(AlarmIntentService.KEY_ALARM_HOUR);
+ int minute = extras.getInt(AlarmIntentService.KEY_ALARM_MINUTE);
+
+ return new Alarm(id, month, date, hour, minute);
+ }
+
+ public static Bundle writeAlarm(Alarm alarm){
+ Bundle extras = new Bundle();
+ extras.putInt(AlarmIntentService.KEY_ALARM_ID, alarm.id);
+ extras.putInt(AlarmIntentService.KEY_ALARM_MONTH, alarm.month);
+ extras.putInt(AlarmIntentService.KEY_ALARM_DATE, alarm.date);
+ extras.putInt(AlarmIntentService.KEY_ALARM_HOUR, alarm.hour);
+ extras.putInt(AlarmIntentService.KEY_ALARM_MINUTE, alarm.minute);
+
+ return extras;
+ }
}
diff --git a/samples/browseable/ElevationBasic/res/layout/elevation_basic.xml b/samples/browseable/ElevationBasic/res/layout/elevation_basic.xml
index 83ab1d282..d6c951066 100644
--- a/samples/browseable/ElevationBasic/res/layout/elevation_basic.xml
+++ b/samples/browseable/ElevationBasic/res/layout/elevation_basic.xml
@@ -16,14 +16,13 @@
-->
<FrameLayout 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">
<View
android:id="@+id/floating_shape"
android:layout_width="80dp"
android:layout_height="80dp"
- android:layout_marginRight="40dp"
+ android:layout_marginEnd="40dp"
android:background="@drawable/shape"
android:elevation="30dp"
android:layout_gravity="center"/>
@@ -31,7 +30,7 @@
android:id="@+id/floating_shape_2"
android:layout_width="80dp"
android:layout_height="80dp"
- android:layout_marginLeft="25dp"
+ android:layout_marginStart="25dp"
android:background="@drawable/shape2"
android:layout_gravity="center"/>
</FrameLayout>
diff --git a/samples/browseable/ElevationBasic/src/com.example.android.elevationbasic/ElevationBasicFragment.java b/samples/browseable/ElevationBasic/src/com.example.android.elevationbasic/ElevationBasicFragment.java
index 71edea5b3..4a005907f 100644
--- a/samples/browseable/ElevationBasic/src/com.example.android.elevationbasic/ElevationBasicFragment.java
+++ b/samples/browseable/ElevationBasic/src/com.example.android.elevationbasic/ElevationBasicFragment.java
@@ -19,7 +19,6 @@ package com.example.android.elevationbasic;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
-import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
diff --git a/samples/browseable/FingerprintDialog/AndroidManifest.xml b/samples/browseable/FingerprintDialog/AndroidManifest.xml
index 77d994977..337f64199 100644
--- a/samples/browseable/FingerprintDialog/AndroidManifest.xml
+++ b/samples/browseable/FingerprintDialog/AndroidManifest.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
+<?xml version="1.0" encoding="UTF-8"?><!--
Copyright 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,24 +13,28 @@
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.fingerprintdialog"
- android:versionCode="1"
- android:versionName="1.0">
+<manifest package="com.example.android.fingerprintdialog"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:versionCode="1"
+ android:versionName="1.0">
- <uses-permission android:name="android.permission.USE_FINGERPRINT"/>
+ <uses-permission android:name="android.permission.USE_FINGERPRINT" />
<application
- android:allowBackup="true"
- android:label="@string/application_name"
- android:icon="@mipmap/ic_launcher"
- android:theme="@style/Theme.AppCompat.Light">
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/application_name"
+ android:supportsRtl="true"
+ android:theme="@style/Theme.AppCompat.Light"
+ tools:ignore="GoogleAppIndexingWarning">
- <activity android:name=".MainActivity"
- android:label="@string/application_name">
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/application_name">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
diff --git a/samples/browseable/FingerprintDialog/res/layout/activity_main.xml b/samples/browseable/FingerprintDialog/res/layout/activity_main.xml
index 075899f8f..f0a596fcd 100644
--- a/samples/browseable/FingerprintDialog/res/layout/activity_main.xml
+++ b/samples/browseable/FingerprintDialog/res/layout/activity_main.xml
@@ -31,7 +31,8 @@
android:layout_marginBottom="32dp"
android:layout_gravity="center_horizontal"
android:scaleType="fitCenter"
- android:src="@drawable/android_robot"/>
+ android:src="@drawable/android_robot"
+ android:contentDescription="@string/description_bugdroid_icon"/>
<LinearLayout
android:layout_width="match_parent"
diff --git a/samples/browseable/FingerprintDialog/res/layout/fingerprint_dialog_content.xml b/samples/browseable/FingerprintDialog/res/layout/fingerprint_dialog_content.xml
index 3929ebae6..5bb65b2ac 100644
--- a/samples/browseable/FingerprintDialog/res/layout/fingerprint_dialog_content.xml
+++ b/samples/browseable/FingerprintDialog/res/layout/fingerprint_dialog_content.xml
@@ -41,7 +41,8 @@
android:layout_alignParentStart="true"
android:layout_below="@+id/fingerprint_description"
android:layout_marginTop="20dp"
- android:src="@drawable/ic_fp_40px" />
+ android:src="@drawable/ic_fp_40px"
+ android:contentDescription="@string/description_fingerprint_icon"/>
<TextView
android:id="@+id/fingerprint_status"
diff --git a/samples/browseable/FingerprintDialog/res/menu/menu_main.xml b/samples/browseable/FingerprintDialog/res/menu/menu_main.xml
index 73f5e89a0..6a6ba0f99 100644
--- a/samples/browseable/FingerprintDialog/res/menu/menu_main.xml
+++ b/samples/browseable/FingerprintDialog/res/menu/menu_main.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (C) 2015 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +14,12 @@
~ limitations under the License
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
- <item android:id="@+id/action_settings" android:title="@string/action_settings"
- android:orderInCategory="100" android:showAsAction="never" />
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:context=".MainActivity">
+ <item
+ android:id="@+id/action_settings"
+ android:orderInCategory="100"
+ android:title="@string/action_settings"
+ app:showAsAction="never" />
</menu>
diff --git a/samples/browseable/FingerprintDialog/res/values/strings.xml b/samples/browseable/FingerprintDialog/res/values/strings.xml
index 86f200c97..b08560601 100644
--- a/samples/browseable/FingerprintDialog/res/values/strings.xml
+++ b/samples/browseable/FingerprintDialog/res/values/strings.xml
@@ -25,7 +25,7 @@
<string name="cancel">Cancel</string>
<string name="use_password">Use password</string>
<string name="sign_in">Sign in</string>
- <string name="ok">Ok</string>
+ <string name="ok">OK</string>
<string name="password">Password</string>
<string name="fingerprint_description">Confirm fingerprint to continue</string>
<string name="fingerprint_hint">Touch sensor</string>
@@ -45,4 +45,6 @@
<string name="use_fingerprint_in_future">Use fingerprint in the future</string>
<string name="use_fingerprint_to_authenticate_title">Use fingerprint to authenticate</string>
<string name="use_fingerprint_to_authenticate_key" >use_fingerprint_to_authenticate_key</string>
+ <string name="description_bugdroid_icon">Android bugdroid image</string>
+ <string name="description_fingerprint_icon">Fingerprint icon</string>
</resources>
diff --git a/samples/browseable/FingerprintDialog/src/com.example.android.fingerprintdialog/FingerprintAuthenticationDialogFragment.java b/samples/browseable/FingerprintDialog/src/com.example.android.fingerprintdialog/FingerprintAuthenticationDialogFragment.java
index 053757330..9f4a68417 100644
--- a/samples/browseable/FingerprintDialog/src/com.example.android.fingerprintdialog/FingerprintAuthenticationDialogFragment.java
+++ b/samples/browseable/FingerprintDialog/src/com.example.android.fingerprintdialog/FingerprintAuthenticationDialogFragment.java
@@ -16,8 +16,8 @@
package com.example.android.fingerprintdialog;
-import android.app.Activity;
import android.app.DialogFragment;
+import android.content.Context;
import android.content.SharedPreferences;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
@@ -134,11 +134,11 @@ public class FingerprintAuthenticationDialogFragment extends DialogFragment
}
@Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- mActivity = (MainActivity) activity;
- mInputMethodManager = mActivity.getSystemService(InputMethodManager.class);
- mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(mActivity);
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mActivity = (MainActivity) getActivity();
+ mInputMethodManager = context.getSystemService(InputMethodManager.class);
+ mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
}
/**
diff --git a/samples/browseable/GridViewPager/AndroidManifest.xml b/samples/browseable/GridViewPager/AndroidManifest.xml
index e25cd6373..bd6df9452 100644
--- a/samples/browseable/GridViewPager/AndroidManifest.xml
+++ b/samples/browseable/GridViewPager/AndroidManifest.xml
@@ -27,6 +27,11 @@
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.DeviceDefault.Light" >
+
+ <meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="true" />
+
<activity
android:name="com.example.android.wearable.gridviewpager.MainActivity"
android:label="@string/app_name" >
diff --git a/samples/browseable/ImmersiveMode/res/menu/main.xml b/samples/browseable/ImmersiveMode/res/menu/main.xml
index 2c3515dd4..498f2c60e 100644
--- a/samples/browseable/ImmersiveMode/res/menu/main.xml
+++ b/samples/browseable/ImmersiveMode/res/menu/main.xml
@@ -14,8 +14,9 @@
limitations under the License.
-->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/sample_action"
- android:showAsAction="ifRoom|withText"
+ app:showAsAction="ifRoom|withText"
android:title="@string/sample_action" />
</menu>
diff --git a/samples/browseable/JobScheduler/AndroidManifest.xml b/samples/browseable/JobScheduler/AndroidManifest.xml
index 06a927b94..8ef81ba4f 100644
--- a/samples/browseable/JobScheduler/AndroidManifest.xml
+++ b/samples/browseable/JobScheduler/AndroidManifest.xml
@@ -38,7 +38,7 @@
</activity>
<service
- android:name=".service.TestJobService"
+ android:name=".service.MyJobService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true"/>
</application>
diff --git a/samples/browseable/JobScheduler/res/layout/sample_main.xml b/samples/browseable/JobScheduler/res/layout/sample_main.xml
index 94b16240d..a11983be8 100644
--- a/samples/browseable/JobScheduler/res/layout/sample_main.xml
+++ b/samples/browseable/JobScheduler/res/layout/sample_main.xml
@@ -21,143 +21,204 @@ limitations under the License.
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp">
+
<TextView
android:id="@+id/onstart_textview"
android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:layout_margin="12dp"
android:layout_weight="1"
android:background="@color/none_received"
android:gravity="center"
- android:text="@string/onstarttask"/>
+ android:text="@string/onstarttask" />
+
<TextView
android:id="@+id/onstop_textview"
android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:layout_margin="12dp"
android:layout_weight="1"
android:background="@color/none_received"
android:gravity="center"
- android:text="@string/onstoptask"/>
+ android:text="@string/onstoptask" />
+
</LinearLayout>
- <Button
- android:id="@+id/finished_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="20dp"
- android:layout_marginBottom="5dp"
- android:onClick="finishJob"
- android:text="@string/finish_job_button_text"/>
<TextView
android:id="@+id/task_params"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/defaultparamtext"
+ android:layout_marginBottom="10dp"
+ android:layout_weight="1"
android:gravity="center"
- android:textSize="20dp"
android:padding="15dp"
- android:layout_marginBottom="10dp" />
+ android:textSize="20sp" />
- <TextView
+ <Button
+ android:id="@+id/finished_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/constraints"
- android:layout_margin="15dp"
- android:textSize="18dp"/>
- <LinearLayout
+ android:padding="20dp"
+ android:layout_marginBottom="5dp"
+ android:layout_marginLeft="40dp"
+ android:layout_marginRight="40dp"
+ android:onClick="finishJob"
+ android:text="@string/finish_job_button_text"/>
+
+ <TableLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_marginLeft="10dp">
- <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_margin="8dp">
+
+ <TableRow
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="match_parent">
+
<TextView
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginRight="12dp"
+ android:gravity="right|center_vertical"
+ android:text="@string/work_duration"
+ android:textSize="14sp" />
+
+ <EditText
+ android:id="@+id/duration_time"
+ android:layout_width="48dp"
android:layout_height="wrap_content"
+ android:inputType="number"
+ android:text="2" />
+
+ </TableRow>
+
+ <TableRow
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginRight="12dp"
+ android:gravity="right|center_vertical"
android:text="@string/connectivity"
- android:layout_marginRight="10dp"/>
+ android:textSize="14sp" />
+
<RadioGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
- <RadioButton android:id="@+id/checkbox_any"
+
+ <RadioButton
+ android:id="@+id/checkbox_any"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/any"/>
- <RadioButton android:id="@+id/checkbox_unmetered"
+ android:checked="true"
+ android:text="@string/any" />
+
+ <RadioButton
+ android:id="@+id/checkbox_unmetered"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/unmetered"/>
+ android:text="@string/unmetered" />
</RadioGroup>
- </LinearLayout>
- <LinearLayout
+ </TableRow>
+
+ <TableRow
android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/timing"/>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="15dp"
- android:textSize="17dp"
- android:text="@string/delay"/>
- <EditText
- android:id="@+id/delay_time"
- android:layout_width="60dp"
- android:layout_height="wrap_content"
- android:inputType="number"/>
+ android:layout_height="match_parent">
+
<TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/deadline"
- android:textSize="17dp"/>
- <EditText
- android:id="@+id/deadline_time"
- android:layout_width="60dp"
- android:layout_height="wrap_content"
- android:inputType="number"/>
- </LinearLayout>
- <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginRight="12dp"
+ android:gravity="right|center_vertical"
+ android:text="@string/delay"
+ android:textSize="14sp" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/timing" />
+
+ <EditText
+ android:id="@+id/delay_time"
+ android:layout_width="48dp"
+ android:layout_height="wrap_content"
+ android:inputType="number"
+ android:text="0" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/deadline"
+ android:textSize="14sp" />
+
+ <EditText
+ android:id="@+id/deadline_time"
+ android:layout_width="48dp"
+ android:layout_height="wrap_content"
+ android:inputType="number"
+ android:text="15" />
+
+ </LinearLayout>
+
+ </TableRow>
+
+ <TableRow
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+
<TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginRight="12dp"
+ android:gravity="right|center_vertical"
android:text="@string/charging_caption"
- android:layout_marginRight="15dp"/>
+ android:textSize="14sp" />
+
<CheckBox
+ android:id="@+id/checkbox_charging"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:id="@+id/checkbox_charging"
- android:text="@string/charging_text"/>
- </LinearLayout>
- <LinearLayout
+ android:text="@string/charging_text" />
+
+ </TableRow>
+
+ <TableRow
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+
<TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/idle_caption"
- android:layout_marginRight="15dp"/>
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginRight="12dp"
+ android:gravity="right|center_vertical"
+ android:text="@string/idle_caption" />
+
<CheckBox
+ android:id="@+id/checkbox_idle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:id="@+id/checkbox_idle"
- android:text="@string/idle_mode_text"/>
- </LinearLayout>
+ android:text="@string/idle_mode_text" />
+ </TableRow>
+
+ </TableLayout>
- </LinearLayout>
<Button
android:id="@+id/schedule_button"
android:layout_width="match_parent"
diff --git a/samples/browseable/JobScheduler/res/values/strings.xml b/samples/browseable/JobScheduler/res/values/strings.xml
index 89524b25a..0d551eba8 100644
--- a/samples/browseable/JobScheduler/res/values/strings.xml
+++ b/samples/browseable/JobScheduler/res/values/strings.xml
@@ -21,16 +21,19 @@ limitations under the License.
<string name="defaultparamtext">task params will show up here.</string>
<string name="schedule_job_button_text">Schedule Job</string>
<string name="cancel_all_jobs_button_text">Cancel all</string>
- <string name="finish_job_button_text">taskFinished</string>
+ <string name="finish_job_button_text">Finish last task</string>
<string name="idle_mode_text">Requires device in idle mode.</string>
<string name="charging_caption">Charging:</string>
<string name="charging_text">Requires device plugged in.</string>
<string name="idle_caption">Idle:</string>
- <string name="constraints">Constraints</string>
<string name="connectivity">Connectivity:</string>
<string name="any">Any</string>
<string name="unmetered">WiFi</string>
<string name="timing">Timing:</string>
<string name="delay">Delay:</string>
<string name="deadline">Deadline:</string>
+ <string name="work_duration">Work duration:</string>
+ <string name="cancelled_job">Cancelled job %d</string>
+ <string name="no_jobs_to_cancel">No jobs to cancel</string>
+ <string name="all_jobs_cancelled">All jobs cancelled</string>
</resources>
diff --git a/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/MainActivity.java b/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/MainActivity.java
index 624e22d02..fbb817261 100644
--- a/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/MainActivity.java
+++ b/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/MainActivity.java
@@ -18,17 +18,19 @@ package com.example.android.jobscheduler;
import android.app.Activity;
import android.app.job.JobInfo;
-import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
+import android.os.PersistableBundle;
+import android.support.annotation.ColorRes;
+import android.support.annotation.Nullable;
import android.text.TextUtils;
+import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
@@ -36,105 +38,97 @@ import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
-import com.example.android.jobscheduler.service.TestJobService;
+import com.example.android.jobscheduler.service.MyJobService;
+import java.lang.ref.WeakReference;
+import java.util.List;
+
+
+/**
+ * Schedules and configures jobs to be executed by a {@link JobScheduler}.
+ * <p>
+ * {@link MyJobService} can send messages to this via a {@link Messenger}
+ * that is sent in the Intent that starts the Service.
+ */
public class MainActivity extends Activity {
- private static final String TAG = "MainActivity";
+ private static final String TAG = MainActivity.class.getSimpleName();
- public static final int MSG_UNCOLOUR_START = 0;
- public static final int MSG_UNCOLOUR_STOP = 1;
- public static final int MSG_SERVICE_OBJ = 2;
+ public static final int MSG_UNCOLOR_START = 0;
+ public static final int MSG_UNCOLOR_STOP = 1;
+ public static final int MSG_COLOR_START = 2;
+ public static final int MSG_COLOR_STOP = 3;
+
+ public static final String MESSENGER_INTENT_KEY
+ = BuildConfig.APPLICATION_ID + ".MESSENGER_INTENT_KEY";
+ public static final String WORK_DURATION_KEY =
+ BuildConfig.APPLICATION_ID + ".WORK_DURATION_KEY";
+
+ private EditText mDelayEditText;
+ private EditText mDeadlineEditText;
+ private EditText mDurationTimeEditText;
+ private RadioButton mWiFiConnectivityRadioButton;
+ private RadioButton mAnyConnectivityRadioButton;
+ private CheckBox mRequiresChargingCheckBox;
+ private CheckBox mRequiresIdleCheckbox;
+
+ private ComponentName mServiceComponent;
+
+ private int mJobId = 0;
+
+ // Handler for incoming messages from the service.
+ private IncomingMessageHandler mHandler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sample_main);
- Resources res = getResources();
- defaultColor = res.getColor(R.color.none_received);
- startJobColor = res.getColor(R.color.start_received);
- stopJobColor = res.getColor(R.color.stop_received);
// Set up UI.
- mShowStartView = (TextView) findViewById(R.id.onstart_textview);
- mShowStopView = (TextView) findViewById(R.id.onstop_textview);
- mParamsTextView = (TextView) findViewById(R.id.task_params);
mDelayEditText = (EditText) findViewById(R.id.delay_time);
+ mDurationTimeEditText = (EditText) findViewById(R.id.duration_time);
mDeadlineEditText = (EditText) findViewById(R.id.deadline_time);
mWiFiConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_unmetered);
mAnyConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_any);
mRequiresChargingCheckBox = (CheckBox) findViewById(R.id.checkbox_charging);
mRequiresIdleCheckbox = (CheckBox) findViewById(R.id.checkbox_idle);
- mServiceComponent = new ComponentName(this, TestJobService.class);
- // Start service and provide it a way to communicate with us.
- Intent startServiceIntent = new Intent(this, TestJobService.class);
- startServiceIntent.putExtra("messenger", new Messenger(mHandler));
- startService(startServiceIntent);
- }
- // UI fields.
- int defaultColor;
- int startJobColor;
- int stopJobColor;
-
- private TextView mShowStartView;
- private TextView mShowStopView;
- private TextView mParamsTextView;
- private EditText mDelayEditText;
- private EditText mDeadlineEditText;
- private RadioButton mWiFiConnectivityRadioButton;
- private RadioButton mAnyConnectivityRadioButton;
- private CheckBox mRequiresChargingCheckBox;
- private CheckBox mRequiresIdleCheckbox;
+ mServiceComponent = new ComponentName(this, MyJobService.class);
- ComponentName mServiceComponent;
- /** Service object to interact scheduled jobs. */
- TestJobService mTestService;
-
- private static int kJobId = 0;
+ mHandler = new IncomingMessageHandler(this);
+ }
- Handler mHandler = new Handler(/* default looper */) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_UNCOLOUR_START:
- mShowStartView.setBackgroundColor(defaultColor);
- break;
- case MSG_UNCOLOUR_STOP:
- mShowStopView.setBackgroundColor(defaultColor);
- break;
- case MSG_SERVICE_OBJ:
- mTestService = (TestJobService) msg.obj;
- mTestService.setUiCallback(MainActivity.this);
- }
- }
- };
+ @Override
+ protected void onStop() {
+ // A service can be "started" and/or "bound". In this case, it's "started" by this Activity
+ // and "bound" to the JobScheduler (also called "Scheduled" by the JobScheduler). This call
+ // to stopService() won't prevent scheduled jobs to be processed. However, failing
+ // to call stopService() would keep it alive indefinitely.
+ stopService(new Intent(this, MyJobService.class));
+ super.onStop();
+ }
- private boolean ensureTestService() {
- if (mTestService == null) {
- Toast.makeText(MainActivity.this, "Service null, never got callback?",
- Toast.LENGTH_SHORT).show();
- return false;
- }
- return true;
+ @Override
+ protected void onStart() {
+ super.onStart();
+ // Start service and provide it a way to communicate with this class.
+ Intent startServiceIntent = new Intent(this, MyJobService.class);
+ Messenger messengerIncoming = new Messenger(mHandler);
+ startServiceIntent.putExtra(MESSENGER_INTENT_KEY, messengerIncoming);
+ startService(startServiceIntent);
}
/**
- * UI onclick listener to schedule a job. What this job is is defined in
- * TestJobService#scheduleJob().
+ * Executed when user clicks on SCHEDULE JOB.
*/
public void scheduleJob(View v) {
- if (!ensureTestService()) {
- return;
- }
-
- JobInfo.Builder builder = new JobInfo.Builder(kJobId++, mServiceComponent);
+ JobInfo.Builder builder = new JobInfo.Builder(mJobId++, mServiceComponent);
String delay = mDelayEditText.getText().toString();
- if (delay != null && !TextUtils.isEmpty(delay)) {
+ if (!TextUtils.isEmpty(delay)) {
builder.setMinimumLatency(Long.valueOf(delay) * 1000);
}
String deadline = mDeadlineEditText.getText().toString();
- if (deadline != null && !TextUtils.isEmpty(deadline)) {
+ if (!TextUtils.isEmpty(deadline)) {
builder.setOverrideDeadline(Long.valueOf(deadline) * 1000);
}
boolean requiresUnmetered = mWiFiConnectivityRadioButton.isChecked();
@@ -147,49 +141,128 @@ public class MainActivity extends Activity {
builder.setRequiresDeviceIdle(mRequiresIdleCheckbox.isChecked());
builder.setRequiresCharging(mRequiresChargingCheckBox.isChecked());
- mTestService.scheduleJob(builder.build());
+ // Extras, work duration.
+ PersistableBundle extras = new PersistableBundle();
+ String workDuration = mDurationTimeEditText.getText().toString();
+ if (TextUtils.isEmpty(workDuration)) {
+ workDuration = "1";
+ }
+ extras.putLong(WORK_DURATION_KEY, Long.valueOf(workDuration) * 1000);
+
+ builder.setExtras(extras);
+ // Schedule job
+ Log.d(TAG, "Scheduling job");
+ JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ tm.schedule(builder.build());
}
+ /**
+ * Executed when user clicks on CANCEL ALL.
+ */
public void cancelAllJobs(View v) {
- JobScheduler tm =
- (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
tm.cancelAll();
+ Toast.makeText(MainActivity.this, R.string.all_jobs_cancelled, Toast.LENGTH_SHORT).show();
}
/**
- * UI onclick listener to call jobFinished() in our service.
+ * Executed when user clicks on FINISH LAST TASK.
*/
public void finishJob(View v) {
- if (!ensureTestService()) {
- return;
+ JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ List<JobInfo> allPendingJobs = jobScheduler.getAllPendingJobs();
+ if (allPendingJobs.size() > 0) {
+ // Finish the last one
+ int jobId = allPendingJobs.get(0).getId();
+ jobScheduler.cancel(jobId);
+ Toast.makeText(
+ MainActivity.this, String.format(getString(R.string.cancelled_job), jobId),
+ Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(
+ MainActivity.this, getString(R.string.no_jobs_to_cancel),
+ Toast.LENGTH_SHORT).show();
}
- mTestService.callJobFinished();
- mParamsTextView.setText("");
}
/**
- * Receives callback from the service when a job has landed
- * on the app. Colours the UI and post a message to
- * uncolour it after a second.
+ * A {@link Handler} allows you to send messages associated with a thread. A {@link Messenger}
+ * uses this handler to communicate from {@link MyJobService}. It's also used to make
+ * the start and stop views blink for a short period of time.
*/
- public void onReceivedStartJob(JobParameters params) {
- mShowStartView.setBackgroundColor(startJobColor);
- Message m = Message.obtain(mHandler, MSG_UNCOLOUR_START);
- mHandler.sendMessageDelayed(m, 1000L); // uncolour in 1 second.
- mParamsTextView.setText("Executing: " + params.getJobId() + " " + params.getExtras());
- }
+ private static class IncomingMessageHandler extends Handler {
- /**
- * Receives callback from the service when a job that
- * previously landed on the app must stop executing.
- * Colours the UI and post a message to uncolour it after a
- * second.
- */
- public void onReceivedStopJob() {
- mShowStopView.setBackgroundColor(stopJobColor);
- Message m = Message.obtain(mHandler, MSG_UNCOLOUR_STOP);
- mHandler.sendMessageDelayed(m, 2000L); // uncolour in 1 second.
- mParamsTextView.setText("");
+ // Prevent possible leaks with a weak reference.
+ private WeakReference<MainActivity> mActivity;
+
+ IncomingMessageHandler(MainActivity activity) {
+ super(/* default looper */);
+ this.mActivity = new WeakReference<>(activity);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ MainActivity mainActivity = mActivity.get();
+ if (mainActivity == null) {
+ // Activity is no longer available, exit.
+ return;
+ }
+ View showStartView = mainActivity.findViewById(R.id.onstart_textview);
+ View showStopView = mainActivity.findViewById(R.id.onstop_textview);
+ Message m;
+ switch (msg.what) {
+ /*
+ * Receives callback from the service when a job has landed
+ * on the app. Turns on indicator and sends a message to turn it off after
+ * a second.
+ */
+ case MSG_COLOR_START:
+ // Start received, turn on the indicator and show text.
+ showStartView.setBackgroundColor(getColor(R.color.start_received));
+ updateParamsTextView(msg.obj, "started");
+
+ // Send message to turn it off after a second.
+ m = Message.obtain(this, MSG_UNCOLOR_START);
+ sendMessageDelayed(m, 1000L);
+ break;
+ /*
+ * Receives callback from the service when a job that previously landed on the
+ * app must stop executing. Turns on indicator and sends a message to turn it
+ * off after two seconds.
+ */
+ case MSG_COLOR_STOP:
+ // Stop received, turn on the indicator and show text.
+ showStopView.setBackgroundColor(getColor(R.color.stop_received));
+ updateParamsTextView(msg.obj, "stopped");
+
+ // Send message to turn it off after a second.
+ m = obtainMessage(MSG_UNCOLOR_STOP);
+ sendMessageDelayed(m, 2000L);
+ break;
+ case MSG_UNCOLOR_START:
+ showStartView.setBackgroundColor(getColor(R.color.none_received));
+ updateParamsTextView(null, "");
+ break;
+ case MSG_UNCOLOR_STOP:
+ showStopView.setBackgroundColor(getColor(R.color.none_received));
+ updateParamsTextView(null, "");
+ break;
+ }
+ }
+
+ private void updateParamsTextView(@Nullable Object jobId, String action) {
+ TextView paramsTextView = (TextView) mActivity.get().findViewById(R.id.task_params);
+ if (jobId == null) {
+ paramsTextView.setText("");
+ return;
+ }
+ String jobIdText = String.valueOf(jobId);
+ paramsTextView.setText(String.format("Job ID %s %s", jobIdText, action));
+ }
+
+ private int getColor(@ColorRes int color) {
+ return mActivity.get().getResources().getColor(color);
+ }
}
}
diff --git a/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/service/MyJobService.java b/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/service/MyJobService.java
new file mode 100644
index 000000000..2f521bb0d
--- /dev/null
+++ b/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/service/MyJobService.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * 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.jobscheduler.service;
+
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+
+import static com.example.android.jobscheduler.MainActivity.MESSENGER_INTENT_KEY;
+import static com.example.android.jobscheduler.MainActivity.MSG_COLOR_START;
+import static com.example.android.jobscheduler.MainActivity.MSG_COLOR_STOP;
+import static com.example.android.jobscheduler.MainActivity.WORK_DURATION_KEY;
+
+
+/**
+ * Service to handle callbacks from the JobScheduler. Requests scheduled with the JobScheduler
+ * ultimately land on this service's "onStartJob" method. It runs jobs for a specific amount of time
+ * and finishes them. It keeps the activity updated with changes via a Messenger.
+ */
+public class MyJobService extends JobService {
+
+ private static final String TAG = MyJobService.class.getSimpleName();
+
+ private Messenger mActivityMessenger;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.i(TAG, "Service created");
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Log.i(TAG, "Service destroyed");
+ }
+
+ /**
+ * When the app's MainActivity is created, it starts this service. This is so that the
+ * activity and this service can communicate back and forth. See "setUiCallback()"
+ */
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ mActivityMessenger = intent.getParcelableExtra(MESSENGER_INTENT_KEY);
+ return START_NOT_STICKY;
+ }
+
+ @Override
+ public boolean onStartJob(final JobParameters params) {
+ // The work that this service "does" is simply wait for a certain duration and finish
+ // the job (on another thread).
+
+ sendMessage(MSG_COLOR_START, params.getJobId());
+
+ long duration = params.getExtras().getLong(WORK_DURATION_KEY);
+
+ // Uses a handler to delay the execution of jobFinished().
+ Handler handler = new Handler();
+ handler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ sendMessage(MSG_COLOR_STOP, params.getJobId());
+ jobFinished(params, false);
+ }
+ }, duration);
+ Log.i(TAG, "on start job: " + params.getJobId());
+
+ // Return true as there's more work to be done with this job.
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ // Stop tracking these job parameters, as we've 'finished' executing.
+ sendMessage(MSG_COLOR_STOP, params.getJobId());
+ Log.i(TAG, "on stop job: " + params.getJobId());
+
+ // Return false to drop the job.
+ return false;
+ }
+
+ private void sendMessage(int messageID, @Nullable Object params) {
+ // If this service is launched by the JobScheduler, there's no callback Messenger. It
+ // only exists when the MainActivity calls startService() with the callback in the Intent.
+ if (mActivityMessenger == null) {
+ Log.d(TAG, "Service is bound, not started. There's no callback to send a message to.");
+ return;
+ }
+ Message m = Message.obtain();
+ m.what = messageID;
+ m.obj = params;
+ try {
+ mActivityMessenger.send(m);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error passing service object back to activity.");
+ }
+ }
+}
diff --git a/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/service/TestJobService.java b/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/service/TestJobService.java
deleted file mode 100644
index 8608be570..000000000
--- a/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/service/TestJobService.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * 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.jobscheduler.service;
-
-import android.app.job.JobInfo;
-import android.app.job.JobScheduler;
-import android.app.job.JobParameters;
-import android.app.job.JobService;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.example.android.jobscheduler.MainActivity;
-
-import java.util.LinkedList;
-
-
-/**
- * Service to handle callbacks from the JobScheduler. Requests scheduled with the JobScheduler
- * ultimately land on this service's "onStartJob" method. Currently all this does is post a message
- * to the app's main activity to change the state of the UI.
- */
-public class TestJobService extends JobService {
- private static final String TAG = "SyncService";
-
- @Override
- public void onCreate() {
- super.onCreate();
- Log.i(TAG, "Service created");
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- Log.i(TAG, "Service destroyed");
- }
-
- /**
- * When the app's MainActivity is created, it starts this service. This is so that the
- * activity and this service can communicate back and forth. See "setUiCalback()"
- */
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- Messenger callback = intent.getParcelableExtra("messenger");
- Message m = Message.obtain();
- m.what = MainActivity.MSG_SERVICE_OBJ;
- m.obj = this;
- try {
- callback.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Error passing service object back to activity.");
- }
- return START_NOT_STICKY;
- }
-
- @Override
- public boolean onStartJob(JobParameters params) {
- // We don't do any real 'work' in this sample app. All we'll
- // do is track which jobs have landed on our service, and
- // update the UI accordingly.
- jobParamsMap.add(params);
- if (mActivity != null) {
- mActivity.onReceivedStartJob(params);
- }
- Log.i(TAG, "on start job: " + params.getJobId());
- return true;
- }
-
- @Override
- public boolean onStopJob(JobParameters params) {
- // Stop tracking these job parameters, as we've 'finished' executing.
- jobParamsMap.remove(params);
- if (mActivity != null) {
- mActivity.onReceivedStopJob();
- }
- Log.i(TAG, "on stop job: " + params.getJobId());
- return true;
- }
-
- MainActivity mActivity;
- private final LinkedList<JobParameters> jobParamsMap = new LinkedList<JobParameters>();
-
- public void setUiCallback(MainActivity activity) {
- mActivity = activity;
- }
-
- /** Send job to the JobScheduler. */
- public void scheduleJob(JobInfo t) {
- Log.d(TAG, "Scheduling job");
- JobScheduler tm =
- (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
- tm.schedule(t);
- }
-
- /**
- * Not currently used, but as an exercise you can hook this
- * up to a button in the UI to finish a job that has landed
- * in onStartJob().
- */
- public boolean callJobFinished() {
- JobParameters params = jobParamsMap.poll();
- if (params == null) {
- return false;
- } else {
- jobFinished(params, false);
- return true;
- }
- }
-
-}
diff --git a/samples/browseable/JumpingJack/AndroidManifest.xml b/samples/browseable/JumpingJack/AndroidManifest.xml
index f6cf22047..0e0475a27 100644
--- a/samples/browseable/JumpingJack/AndroidManifest.xml
+++ b/samples/browseable/JumpingJack/AndroidManifest.xml
@@ -18,7 +18,7 @@
package="com.example.android.wearable.jumpingjack">
<uses-sdk android:minSdkVersion="20"
- android:targetSdkVersion="22" />
+ android:targetSdkVersion="25" />
<uses-feature android:name="android.hardware.type.watch" />
@@ -29,6 +29,11 @@
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.DeviceDefault.Light">
+
+ <meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="true" />
+
<activity
android:name=".MainActivity"
android:label="@string/app_name">
diff --git a/samples/browseable/LNotifications/res/layout/activity_notification.xml b/samples/browseable/LNotifications/res/layout/activity_notification.xml
index cd0cd6878..8723923fd 100644
--- a/samples/browseable/LNotifications/res/layout/activity_notification.xml
+++ b/samples/browseable/LNotifications/res/layout/activity_notification.xml
@@ -14,14 +14,26 @@
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.example.android.lnotifications.LNotificationActivity">
-</FrameLayout>
+
+ <android.support.design.widget.TabLayout
+ android:id="@+id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:tabMode="fixed"
+ app:tabGravity="fill" />
+
+ <android.support.v4.view.ViewPager
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+ </android.support.v4.view.ViewPager>
+</LinearLayout>
diff --git a/samples/browseable/LNotifications/src/com.example.android.lnotifications/HeadsUpNotificationFragment.java b/samples/browseable/LNotifications/src/com.example.android.lnotifications/HeadsUpNotificationFragment.java
index d304cf4ae..89904031a 100644
--- a/samples/browseable/LNotifications/src/com.example.android.lnotifications/HeadsUpNotificationFragment.java
+++ b/samples/browseable/LNotifications/src/com.example.android.lnotifications/HeadsUpNotificationFragment.java
@@ -16,13 +16,13 @@
package com.example.android.lnotifications;
-import android.app.Fragment;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -110,8 +110,7 @@ public class HeadsUpNotificationFragment extends Fragment {
*
* @return A Notification instance.
*/
- //@VisibleForTesting
- Notification createNotification(boolean makeHeadsUpNotification) {
+ private Notification createNotification(boolean makeHeadsUpNotification) {
Notification.Builder notificationBuilder = new Notification.Builder(getActivity())
.setSmallIcon(R.drawable.ic_launcher_notification)
.setPriority(Notification.PRIORITY_DEFAULT)
diff --git a/samples/browseable/LNotifications/src/com.example.android.lnotifications/LNotificationActivity.java b/samples/browseable/LNotifications/src/com.example.android.lnotifications/LNotificationActivity.java
index fbc3e6232..8b44ed327 100644
--- a/samples/browseable/LNotifications/src/com.example.android.lnotifications/LNotificationActivity.java
+++ b/samples/browseable/LNotifications/src/com.example.android.lnotifications/LNotificationActivity.java
@@ -16,65 +16,74 @@
package com.example.android.lnotifications;
-import android.app.ActionBar;
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.FragmentTransaction;
import android.os.Bundle;
+import android.support.design.widget.TabLayout;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+
+import static com.example.android.lnotifications.R.id.pager;
/**
* Launcher Activity for the L Notification samples application.
*/
-public class LNotificationActivity extends Activity {
+public class LNotificationActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notification);
- setTitle(R.string.title_lnotification_activity);
- ActionBar actionBar = getActionBar();
- // Use ViewPager in the support library where possible.
- // At this time, the support library for L is not ready so using the deprecated method
- // to create tabs.
- actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
- ActionBar.Tab tabHeadsUpNotification = actionBar.newTab().setText("Heads Up");
- ActionBar.Tab tabVisibilityMetadata = actionBar.newTab().setText("Visibility");
- ActionBar.Tab tabOtherMetadata = actionBar.newTab().setText("Others");
- tabHeadsUpNotification.setTabListener(new FragmentTabListener(HeadsUpNotificationFragment
- .newInstance()));
- tabVisibilityMetadata.setTabListener(new FragmentTabListener(VisibilityMetadataFragment
- .newInstance()));
- tabOtherMetadata.setTabListener(new FragmentTabListener(OtherMetadataFragment.newInstance
- ()));
- actionBar.addTab(tabHeadsUpNotification, 0);
- actionBar.addTab(tabVisibilityMetadata, 1);
- actionBar.addTab(tabOtherMetadata, 2);
+ // Show 3 tabs with the different notification options.
+ ViewPager viewPager = (ViewPager) findViewById(pager);
+ TabLayout tabs = (TabLayout) findViewById(R.id.tabs);
+
+ NotificationsPagerAdapter pagerAdapter =
+ new NotificationsPagerAdapter(getSupportFragmentManager());
+ viewPager.setAdapter(pagerAdapter);
+ tabs.setupWithViewPager(viewPager);
}
- /**
- * TabListener that replaces a Fragment when a tab is clicked.
- */
- private static class FragmentTabListener implements ActionBar.TabListener {
- public Fragment fragment;
+ private static class NotificationsPagerAdapter extends FragmentPagerAdapter {
- public FragmentTabListener(Fragment fragment) {
- this.fragment = fragment;
+ NotificationsPagerAdapter(FragmentManager fm) {
+ super(fm);
}
@Override
- public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
- //do nothing.
+ public Fragment getItem(int position) {
+ switch (position) {
+ case 0:
+ return HeadsUpNotificationFragment.newInstance();
+ case 1:
+ return VisibilityMetadataFragment.newInstance();
+ case 2:
+ return OtherMetadataFragment.newInstance();
+ default:
+ break;
+ }
+ return null;
}
@Override
- public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
- ft.replace(R.id.container, fragment);
+ public int getCount() {
+ return 3;
}
@Override
- public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
- ft.remove(fragment);
+ public CharSequence getPageTitle(int position) {
+ switch (position) {
+ case 0:
+ return "Heads Up";
+ case 1:
+ return "Visibility";
+ case 2:
+ return "Others";
+ default:
+ return super.getPageTitle(position);
+ }
}
}
}
diff --git a/samples/browseable/LNotifications/src/com.example.android.lnotifications/OtherMetadataFragment.java b/samples/browseable/LNotifications/src/com.example.android.lnotifications/OtherMetadataFragment.java
index 51616e700..0da2c2ade 100644
--- a/samples/browseable/LNotifications/src/com.example.android.lnotifications/OtherMetadataFragment.java
+++ b/samples/browseable/LNotifications/src/com.example.android.lnotifications/OtherMetadataFragment.java
@@ -17,7 +17,6 @@
package com.example.android.lnotifications;
import android.app.Activity;
-import android.app.Fragment;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
@@ -30,6 +29,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.MediaStore;
+import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -42,7 +42,6 @@ import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
-import java.util.Random;
/**
* Fragment that demonstrates how to attach metadata introduced in Android L, such as
@@ -58,10 +57,10 @@ public class OtherMetadataFragment extends Fragment {
public static final int REQUEST_CODE_PICK_CONTACT = 1;
/**
- * Incremental Integer used for ID for notifications so that each notification will be
+ * Incremental int used for ID for notifications so that each notification will be
* treated differently.
*/
- private Integer mIncrementalNotificationId = Integer.valueOf(0);
+ private int mIncrementalNotificationId = 0;
private NotificationManager mNotificationManager;
@@ -85,8 +84,7 @@ public class OtherMetadataFragment extends Fragment {
/**
* Holds a URI for the person to be attached to the notification.
*/
- //@VisibleForTesting
- Uri mContactUri;
+ private Uri mContactUri;
/**
* Use this factory method to create a new instance of
@@ -177,8 +175,7 @@ public class OtherMetadataFragment extends Fragment {
*
* @return A Notification instance.
*/
- //@VisibleForTesting
- Notification createNotification(Priority priority, Category category, Uri contactUri) {
+ private Notification createNotification(Priority priority, Category category, Uri contactUri) {
Notification.Builder notificationBuilder = new Notification.Builder(getActivity())
.setContentTitle("Notification with other metadata")
.setSmallIcon(R.drawable.ic_launcher_notification)
@@ -207,7 +204,7 @@ public class OtherMetadataFragment extends Fragment {
private void showNotificationClicked(Priority priority, Category category, Uri contactUri) {
// Assigns a unique (incremented) notification ID in order to treat each notification as a
// different one. This helps demonstrate how a priority flag affects ordering.
- mIncrementalNotificationId = new Integer(mIncrementalNotificationId + 1);
+ mIncrementalNotificationId++;
mNotificationManager.notify(mIncrementalNotificationId, createNotification(priority,
category, contactUri));
Toast.makeText(getActivity(), "Show Notification clicked", Toast.LENGTH_SHORT).show();
@@ -295,8 +292,7 @@ public class OtherMetadataFragment extends Fragment {
* Enum indicating possible categories in {@link Notification} used from
* {@link #mCategorySpinner}.
*/
- //@VisibleForTesting
- static enum Category {
+ private enum Category {
ALARM("alarm"),
CALL("call"),
EMAIL("email"),
@@ -328,8 +324,7 @@ public class OtherMetadataFragment extends Fragment {
* Enum indicating possible priorities in {@link Notification} used from
* {@link #mPrioritySpinner}.
*/
- //@VisibleForTesting
- static enum Priority {
+ private enum Priority {
DEFAULT(Notification.PRIORITY_DEFAULT),
MAX(Notification.PRIORITY_MAX),
HIGH(Notification.PRIORITY_HIGH),
diff --git a/samples/browseable/LNotifications/src/com.example.android.lnotifications/VisibilityMetadataFragment.java b/samples/browseable/LNotifications/src/com.example.android.lnotifications/VisibilityMetadataFragment.java
index 616632b34..c12d1082e 100644
--- a/samples/browseable/LNotifications/src/com.example.android.lnotifications/VisibilityMetadataFragment.java
+++ b/samples/browseable/LNotifications/src/com.example.android.lnotifications/VisibilityMetadataFragment.java
@@ -16,11 +16,11 @@
package com.example.android.lnotifications;
-import android.app.Fragment;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Bundle;
+import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -28,8 +28,6 @@ import android.widget.Button;
import android.widget.RadioGroup;
import android.widget.Toast;
-import java.util.Random;
-
/**
* Fragment that demonstrates how notifications with different visibility metadata differ on
@@ -45,10 +43,10 @@ public class VisibilityMetadataFragment extends Fragment {
private RadioGroup mRadioGroup;
/**
- * Incremental Integer used for ID for notifications so that each notification will be
+ * Incremental int used for ID for notifications so that each notification will be
* treated differently.
*/
- private Integer mIncrementalNotificationId = Integer.valueOf(0);
+ private int mIncrementalNotificationId = 0;
/**
* Button to show a notification.
@@ -106,8 +104,7 @@ public class VisibilityMetadataFragment extends Fragment {
*
* @return A Notification instance.
*/
- //@VisibleForTesting
- Notification createNotification(NotificationVisibility visibility) {
+ private Notification createNotification(NotificationVisibility visibility) {
Notification.Builder notificationBuilder = new Notification.Builder(getActivity())
.setContentTitle("Notification for Visibility metadata");
@@ -150,7 +147,7 @@ public class VisibilityMetadataFragment extends Fragment {
// Assigns a unique (incremented) notification ID in order to treat each notification as a
// different one. This helps demonstrate how a notification with a different visibility
// level differs on the lockscreen.
- mIncrementalNotificationId = new Integer(mIncrementalNotificationId + 1);
+ mIncrementalNotificationId++;
mNotificationManager.notify(mIncrementalNotificationId, createNotification(visibility));
Toast.makeText(getActivity(), "Show Notification clicked", Toast.LENGTH_SHORT).show();
}
@@ -160,8 +157,7 @@ public class VisibilityMetadataFragment extends Fragment {
* representation of visibility levels, an icon ID to create a notification) to
* create a notification.
*/
- //@VisibleForTesting
- static enum NotificationVisibility {
+ private enum NotificationVisibility {
PUBLIC(Notification.VISIBILITY_PUBLIC, "Public", R.drawable.ic_public_notification),
PRIVATE(Notification.VISIBILITY_PRIVATE, "Private", R.drawable.ic_private_notification),
SECRET(Notification.VISIBILITY_SECRET, "Secret", R.drawable.ic_secret_notification);
diff --git a/samples/browseable/NetworkConnect/AndroidManifest.xml b/samples/browseable/NetworkConnect/AndroidManifest.xml
index 00ce7f3d0..654203b61 100644
--- a/samples/browseable/NetworkConnect/AndroidManifest.xml
+++ b/samples/browseable/NetworkConnect/AndroidManifest.xml
@@ -31,8 +31,8 @@
android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
android:theme="@style/Theme.Sample"
- android:allowBackup="true">
-
+ android:allowBackup="true"
+ android:networkSecurityConfig="@xml/network_security_config">
<activity
android:name="com.example.android.networkconnect.MainActivity"
android:label="@string/app_name"
diff --git a/samples/browseable/NetworkConnect/_index.jd b/samples/browseable/NetworkConnect/_index.jd
index 7be3ce205..a816b6286 100644
--- a/samples/browseable/NetworkConnect/_index.jd
+++ b/samples/browseable/NetworkConnect/_index.jd
@@ -6,6 +6,6 @@ sample.group=Connectivity
<p>
This sample demonstrates how to connect to the network and fetch raw HTML using
- HttpURLConnection. AsyncTask is used to perform the fetch on a background thread.
+ HttpsURLConnection. AsyncTask is used to perform the fetch on a background thread.
</p>
diff --git a/samples/browseable/NetworkConnect/res/layout/sample_main.xml b/samples/browseable/NetworkConnect/res/layout/sample_main.xml
index 76fa7d783..00e219c5b 100755
--- a/samples/browseable/NetworkConnect/res/layout/sample_main.xml
+++ b/samples/browseable/NetworkConnect/res/layout/sample_main.xml
@@ -21,20 +21,22 @@
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
- <fragment
- android:name="com.example.android.networkconnect.SimpleTextFragment"
- android:id="@+id/intro_fragment"
+ <TextView
+ android:id="@+id/intro_text"
android:layout_weight="1"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ android:textSize="16sp"
+ android:text="@string/welcome_message"
+ android:freezesText="true"/>
<View
android:layout_width="fill_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"
+ <TextView
+ android:id="@+id/data_text"
android:layout_weight="1"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ android:freezesText="true"/>
</LinearLayout>
diff --git a/samples/browseable/NetworkConnect/res/values/base-strings.xml b/samples/browseable/NetworkConnect/res/values/base-strings.xml
index ae4485e0e..820b92125 100644
--- a/samples/browseable/NetworkConnect/res/values/base-strings.xml
+++ b/samples/browseable/NetworkConnect/res/values/base-strings.xml
@@ -22,7 +22,7 @@
This sample demonstrates how to connect to the network and fetch raw HTML using
- HttpURLConnection. AsyncTask is used to perform the fetch on a background thread.
+ HttpsURLConnection. AsyncTask is used to perform the fetch on a background thread.
]]>
diff --git a/samples/browseable/NetworkConnect/res/values/strings.xml b/samples/browseable/NetworkConnect/res/values/strings.xml
index 1e7915afe..d2be145a8 100755
--- a/samples/browseable/NetworkConnect/res/values/strings.xml
+++ b/samples/browseable/NetworkConnect/res/values/strings.xml
@@ -18,8 +18,8 @@
<string name="welcome_message">Welcome to Network Connect!
Click FETCH to fetch the first 500 characters of raw HTML from www.google.com.
</string>
-
<string name="fetch_text">Fetch</string>
<string name="clear_text">Clear</string>
<string name="connection_error">Connection error.</string>
+ <string name="fetch_cancelled">Fetch cancelled.</string>
</resources>
diff --git a/samples/browseable/NetworkConnect/res/xml/network_security_config.xml b/samples/browseable/NetworkConnect/res/xml/network_security_config.xml
new file mode 100644
index 000000000..4631b891f
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/xml/network_security_config.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+ <!--Set application-wide security config using base-config tag.-->
+ <base-config clearTextTrafficPermitted="false"/>
+ <!--Set domain-specific security config using domain-config tags. -->
+ <!--See https://developer.android.com/training/articles/security-config.html for more information.-->
+</network-security-config> \ No newline at end of file
diff --git a/samples/browseable/NetworkConnect/src/com.example.android.common.logger/Log.java b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/Log.java
deleted file mode 100644
index 17503c568..000000000
--- a/samples/browseable/NetworkConnect/src/com.example.android.common.logger/Log.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * 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/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogFragment.java
deleted file mode 100644
index b302acd4b..000000000
--- a/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogFragment.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
-* 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/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogNode.java b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogNode.java
deleted file mode 100644
index bc37cabc0..000000000
--- a/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogNode.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogView.java b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogView.java
deleted file mode 100644
index c01542b91..000000000
--- a/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogView.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * 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/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogWrapper.java
deleted file mode 100644
index 16a9e7ba2..000000000
--- a/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogWrapper.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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/samples/browseable/NetworkConnect/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/MessageOnlyLogFilter.java
deleted file mode 100644
index 19967dcd4..000000000
--- a/samples/browseable/NetworkConnect/src/com.example.android.common.logger/MessageOnlyLogFilter.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/DownloadCallback.java b/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/DownloadCallback.java
new file mode 100644
index 000000000..b553e8500
--- /dev/null
+++ b/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/DownloadCallback.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 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.networkconnect;
+
+import android.net.NetworkInfo;
+import android.support.annotation.IntDef;
+
+/**
+ * Sample interface containing bare minimum methods needed for an asynchronous task
+ * to update the UI Context.
+ */
+
+public interface DownloadCallback {
+ interface Progress {
+ int ERROR = -1;
+ int CONNECT_SUCCESS = 0;
+ int GET_INPUT_STREAM_SUCCESS = 1;
+ int PROCESS_INPUT_STREAM_IN_PROGRESS = 2;
+ int PROCESS_INPUT_STREAM_SUCCESS = 3;
+ }
+
+ /**
+ * Indicates that the callback handler needs to update its appearance or information based on
+ * the result of the task. Expected to be called from the main thread.
+ */
+ void updateFromDownload(String result);
+
+ /**
+ * Get the device's active network status in the form of a NetworkInfo object.
+ */
+ NetworkInfo getActiveNetworkInfo();
+
+ /**
+ * Indicate to callback handler any progress update.
+ * @param progressCode must be one of the constants defined in DownloadCallback.Progress.
+ * @param percentComplete must be 0-100.
+ */
+ void onProgressUpdate(int progressCode, int percentComplete);
+
+ /**
+ * Indicates that the download operation has finished. This method is called even if the
+ * download hasn't completed successfully.
+ */
+ void finishDownloading();
+
+}
diff --git a/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/MainActivity.java b/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/MainActivity.java
index 3ad46463c..d490f5d10 100755
--- a/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/MainActivity.java
+++ b/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/MainActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -16,55 +16,42 @@
package com.example.android.networkconnect;
-import android.os.AsyncTask;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
-import android.util.TypedValue;
+import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
-
-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;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.UnsupportedEncodingException;
-import java.net.HttpURLConnection;
-import java.net.URL;
+import android.widget.TextView;
/**
- * Sample application demonstrating how to connect to the network and fetch raw
- * HTML. It uses AsyncTask to do the fetch on a background thread. To establish
- * the network connection, it uses HttpURLConnection.
+ * Sample Activity demonstrating how to connect to the network and fetch raw
+ * HTML. It uses a Fragment that encapsulates the network operations on an AsyncTask.
*
- * This sample uses the logging framework to display log output in the log
- * fragment (LogFragment).
+ * This sample uses a TextView to display output.
*/
-public class MainActivity extends FragmentActivity {
-
- public static final String TAG = "Network Connect";
+public class MainActivity extends FragmentActivity implements DownloadCallback {
- // Reference to the fragment showing events, so we can clear it with a button
+ // Reference to the TextView showing fetched data, so we can clear it with a button
// as necessary.
- private LogFragment mLogFragment;
+ private TextView mDataText;
+
+ // Keep a reference to the NetworkFragment which owns the AsyncTask object
+ // that is used to execute network ops.
+ private NetworkFragment mNetworkFragment;
+
+ // Boolean telling us whether a download is in progress, so we don't trigger overlapping
+ // downloads with consecutive button clicks.
+ private boolean mDownloading = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sample_main);
-
- // Initialize text fragment that displays intro text.
- SimpleTextFragment introFragment = (SimpleTextFragment)
- getSupportFragmentManager().findFragmentById(R.id.intro_fragment);
- introFragment.setText(R.string.welcome_message);
- introFragment.getTextView().setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16.0f);
-
- // Initialize the logging framework.
- initializeLogging();
+ mDataText = (TextView) findViewById(R.id.data_text);
+ mNetworkFragment = NetworkFragment.getInstance(getSupportFragmentManager(), "https://www.google.com");
}
@Override
@@ -79,111 +66,65 @@ public class MainActivity extends FragmentActivity {
// When the user clicks FETCH, fetch the first 500 characters of
// raw HTML from www.google.com.
case R.id.fetch_action:
- new DownloadTask().execute("http://www.google.com");
+ startDownload();
return true;
- // Clear the log view fragment.
+ // Clear the text and cancel download.
case R.id.clear_action:
- mLogFragment.getLogView().setText("");
- return true;
+ finishDownloading();
+ mDataText.setText("");
+ return true;
}
return false;
}
- /**
- * Implementation of AsyncTask, to fetch the data in the background away from
- * the UI thread.
- */
- private class DownloadTask extends AsyncTask<String, Void, String> {
-
- @Override
- protected String doInBackground(String... urls) {
- try {
- return loadFromNetwork(urls[0]);
- } catch (IOException e) {
- return getString(R.string.connection_error);
- }
- }
-
- /**
- * Uses the logging framework to display the output of the fetch
- * operation in the log fragment.
- */
- @Override
- protected void onPostExecute(String result) {
- Log.i(TAG, result);
+ private void startDownload() {
+ if (!mDownloading && mNetworkFragment != null) {
+ // Execute the async download.
+ mNetworkFragment.startDownload();
+ mDownloading = true;
}
}
- /** Initiates the fetch operation. */
- private String loadFromNetwork(String urlString) throws IOException {
- InputStream stream = null;
- String str ="";
-
- try {
- stream = downloadUrl(urlString);
- str = readIt(stream, 500);
- } finally {
- if (stream != null) {
- stream.close();
- }
+ @Override
+ public void updateFromDownload(String result) {
+ if (result != null) {
+ mDataText.setText(result);
+ } else {
+ mDataText.setText(getString(R.string.connection_error));
}
- return str;
}
- /**
- * Given a string representation of a URL, sets up a connection and gets
- * an input stream.
- * @param urlString A string representation of a URL.
- * @return An InputStream retrieved from a successful HttpURLConnection.
- * @throws java.io.IOException
- */
- private InputStream downloadUrl(String urlString) throws IOException {
- // BEGIN_INCLUDE(get_inputstream)
- URL url = new URL(urlString);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setReadTimeout(10000 /* milliseconds */);
- conn.setConnectTimeout(15000 /* milliseconds */);
- conn.setRequestMethod("GET");
- conn.setDoInput(true);
- // Start the query
- conn.connect();
- InputStream stream = conn.getInputStream();
- return stream;
- // END_INCLUDE(get_inputstream)
+ @Override
+ public NetworkInfo getActiveNetworkInfo() {
+ ConnectivityManager connectivityManager =
+ (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
+ return networkInfo;
}
- /** Reads an InputStream and converts it to a String.
- * @param stream InputStream containing HTML from targeted site.
- * @param len Length of string that this method returns.
- * @return String concatenated according to len parameter.
- * @throws java.io.IOException
- * @throws java.io.UnsupportedEncodingException
- */
- private String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
- Reader reader = null;
- reader = new InputStreamReader(stream, "UTF-8");
- char[] buffer = new char[len];
- reader.read(buffer);
- return new String(buffer);
+ @Override
+ public void finishDownloading() {
+ mDownloading = false;
+ if (mNetworkFragment != null) {
+ mNetworkFragment.cancelDownload();
+ }
}
- /** Create a chain of targets that will 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);
-
- // A filter that strips out everything except the message text.
- MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
- logWrapper.setNext(msgFilter);
-
- // On screen logging via a fragment with a TextView.
- mLogFragment =
- (LogFragment) getSupportFragmentManager().findFragmentById(R.id.log_fragment);
- msgFilter.setNext(mLogFragment.getLogView());
+ @Override
+ public void onProgressUpdate(int progressCode, int percentComplete) {
+ switch(progressCode) {
+ // You can add UI behavior for progress updates here.
+ case Progress.ERROR:
+ break;
+ case Progress.CONNECT_SUCCESS:
+ break;
+ case Progress.GET_INPUT_STREAM_SUCCESS:
+ break;
+ case Progress.PROCESS_INPUT_STREAM_IN_PROGRESS:
+ mDataText.setText("" + percentComplete + "%");
+ break;
+ case Progress.PROCESS_INPUT_STREAM_SUCCESS:
+ break;
+ }
}
}
diff --git a/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/NetworkFragment.java b/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/NetworkFragment.java
new file mode 100644
index 000000000..cc41075a1
--- /dev/null
+++ b/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/NetworkFragment.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2016 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.networkconnect;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URL;
+
+import javax.net.ssl.HttpsURLConnection;
+
+/**
+ * Implementation of headless Fragment that runs an AsyncTask to fetch data from the network.
+ */
+public class NetworkFragment extends Fragment {
+ public static final String TAG = "NetworkFragment";
+
+ private static final String URL_KEY = "UrlKey";
+
+ private DownloadCallback mCallback;
+ private DownloadTask mDownloadTask;
+ private String mUrlString;
+
+ /**
+ * Static initializer for NetworkFragment that sets the URL of the host it will be downloading
+ * from.
+ */
+ public static NetworkFragment getInstance(FragmentManager fragmentManager, String url) {
+ // Recover NetworkFragment in case we are re-creating the Activity due to a config change.
+ // This is necessary because NetworkFragment might have a task that began running before
+ // the config change and has not finished yet.
+ // The NetworkFragment is recoverable via this method because it calls
+ // setRetainInstance(true) upon creation.
+ NetworkFragment networkFragment = (NetworkFragment) fragmentManager
+ .findFragmentByTag(NetworkFragment.TAG);
+ if (networkFragment == null) {
+ networkFragment = new NetworkFragment();
+ Bundle args = new Bundle();
+ args.putString(URL_KEY, url);
+ networkFragment.setArguments(args);
+ fragmentManager.beginTransaction().add(networkFragment, TAG).commit();
+ }
+ return networkFragment;
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // Retain this Fragment across configuration changes in the host Activity.
+ setRetainInstance(true);
+ mUrlString = getArguments().getString(URL_KEY);
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ // Host Activity will handle callbacks from task.
+ mCallback = (DownloadCallback)context;
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ // Clear reference to host Activity.
+ mCallback = null;
+ }
+
+ @Override
+ public void onDestroy() {
+ // Cancel task when Fragment is destroyed.
+ cancelDownload();
+ super.onDestroy();
+ }
+
+ /**
+ * Start non-blocking execution of DownloadTask.
+ */
+ public void startDownload() {
+ cancelDownload();
+ mDownloadTask = new DownloadTask();
+ mDownloadTask.execute(mUrlString);
+ }
+
+ /**
+ * Cancel (and interrupt if necessary) any ongoing DownloadTask execution.
+ */
+ public void cancelDownload() {
+ if (mDownloadTask != null) {
+ mDownloadTask.cancel(true);
+ mDownloadTask = null;
+ }
+ }
+
+ /**
+ * Implementation of AsyncTask that runs a network operation on a background thread.
+ */
+ private class DownloadTask extends AsyncTask<String, Integer, DownloadTask.Result> {
+
+ /**
+ * Wrapper class that serves as a union of a result value and an exception. When the
+ * download task has completed, either the result value or exception can be a non-null
+ * value. This allows you to pass exceptions to the UI thread that were thrown during
+ * doInBackground().
+ */
+ class Result {
+ public String mResultValue;
+ public Exception mException;
+ public Result(String resultValue) {
+ mResultValue = resultValue;
+ }
+ public Result(Exception exception) {
+ mException = exception;
+ }
+ }
+
+ /**
+ * Cancel background network operation if we do not have network connectivity.
+ */
+ @Override
+ protected void onPreExecute() {
+ if (mCallback != null) {
+ NetworkInfo networkInfo = mCallback.getActiveNetworkInfo();
+ if (networkInfo == null || !networkInfo.isConnected() ||
+ (networkInfo.getType() != ConnectivityManager.TYPE_WIFI
+ && networkInfo.getType() != ConnectivityManager.TYPE_MOBILE)) {
+ // If no connectivity, cancel task and update Callback with null data.
+ mCallback.updateFromDownload(null);
+ cancel(true);
+ }
+ }
+ }
+
+ /**
+ * Defines work to perform on the background thread.
+ */
+ @Override
+ protected Result doInBackground(String... urls) {
+ Result result = null;
+ if (!isCancelled() && urls != null && urls.length > 0) {
+ String urlString = urls[0];
+ try {
+ URL url = new URL(urlString);
+ String resultString = downloadUrl(url);
+ if (resultString != null) {
+ result = new Result(resultString);
+ } else {
+ throw new IOException("No response received.");
+ }
+ } catch(Exception e) {
+ result = new Result(e);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Send DownloadCallback a progress update.
+ */
+ @Override
+ protected void onProgressUpdate(Integer... values) {
+ super.onProgressUpdate(values);
+ if (values.length >= 2) {
+ mCallback.onProgressUpdate(values[0], values[1]);
+ }
+ }
+
+ /**
+ * Updates the DownloadCallback with the result.
+ */
+ @Override
+ protected void onPostExecute(Result result) {
+ if (result != null && mCallback != null) {
+ if (result.mException != null) {
+ mCallback.updateFromDownload(result.mException.getMessage());
+ } else if (result.mResultValue != null) {
+ mCallback.updateFromDownload(result.mResultValue);
+ }
+ mCallback.finishDownloading();
+ }
+ }
+
+ /**
+ * Override to add special behavior for cancelled AsyncTask.
+ */
+ @Override
+ protected void onCancelled(Result result) {
+ }
+
+ /**
+ * Given a URL, sets up a connection and gets the HTTP response body from the server.
+ * If the network request is successful, it returns the response body in String form. Otherwise,
+ * it will throw an IOException.
+ */
+ private String downloadUrl(URL url) throws IOException {
+ InputStream stream = null;
+ HttpsURLConnection connection = null;
+ String result = null;
+ try {
+ connection = (HttpsURLConnection) url.openConnection();
+ // Timeout for reading InputStream arbitrarily set to 3000ms.
+ connection.setReadTimeout(3000);
+ // Timeout for connection.connect() arbitrarily set to 3000ms.
+ connection.setConnectTimeout(3000);
+ // For this use case, set HTTP method to GET.
+ connection.setRequestMethod("GET");
+ // Already true by default but setting just in case; needs to be true since this request
+ // is carrying an input (response) body.
+ connection.setDoInput(true);
+ // Open communications link (network traffic occurs here).
+ connection.connect();
+ publishProgress(DownloadCallback.Progress.CONNECT_SUCCESS);
+ int responseCode = connection.getResponseCode();
+ if (responseCode != HttpsURLConnection.HTTP_OK) {
+ throw new IOException("HTTP error code: " + responseCode);
+ }
+ // Retrieve the response body as an InputStream.
+ stream = connection.getInputStream();
+ publishProgress(DownloadCallback.Progress.GET_INPUT_STREAM_SUCCESS, 0);
+ if (stream != null) {
+ // Converts Stream to String with max length of 500.
+ result = readStream(stream, 500);
+ publishProgress(DownloadCallback.Progress.PROCESS_INPUT_STREAM_SUCCESS, 0);
+ }
+ } finally {
+ // Close Stream and disconnect HTTPS connection.
+ if (stream != null) {
+ stream.close();
+ }
+ if (connection != null) {
+ connection.disconnect();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Converts the contents of an InputStream to a String.
+ */
+ private String readStream(InputStream stream, int maxLength) throws IOException {
+ String result = null;
+ // Read InputStream using the UTF-8 charset.
+ InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
+ // Create temporary buffer to hold Stream data with specified max length.
+ char[] buffer = new char[maxLength];
+ // Populate temporary buffer with Stream data.
+ int numChars = 0;
+ int readSize = 0;
+ while (numChars < maxLength && readSize != -1) {
+ numChars += readSize;
+ int pct = (100 * numChars) / maxLength;
+ publishProgress(DownloadCallback.Progress.PROCESS_INPUT_STREAM_IN_PROGRESS, pct);
+ readSize = reader.read(buffer, numChars, buffer.length - numChars);
+ }
+ if (numChars != -1) {
+ // The stream was not empty.
+ // Create String that is actual length of response body if actual length was less than
+ // max length.
+ numChars = Math.min(numChars, maxLength);
+ result = new String(buffer, 0, numChars);
+ }
+ return result;
+ }
+ }
+}
diff --git a/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/SimpleTextFragment.java b/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/SimpleTextFragment.java
deleted file mode 100644
index 320293760..000000000
--- a/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/SimpleTextFragment.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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.networkconnect;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-/**
- * Simple fragment containing only a TextView. Used by TextPagerAdapter to create
- * tutorial-style pages for apps.
- */
-public class SimpleTextFragment extends Fragment {
-
- // Contains the text that will be displayed by this Fragment
- String mText;
-
- // Contains a resource ID for the text that will be displayed by this fragment.
- int mTextId = -1;
-
- // Keys which will be used to store/retrieve text passed in via setArguments.
- public static final String TEXT_KEY = "text";
- public static final String TEXT_ID_KEY = "text_id";
-
- // For situations where the app wants to modify text at Runtime, exposing the TextView.
- private TextView mTextView;
-
- public SimpleTextFragment() {
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- // Before initializing the textView, check if any arguments were provided via setArguments.
- processArguments();
-
- // Create a new TextView and set its text to whatever was provided.
- mTextView = new TextView(getActivity());
- mTextView.setGravity(Gravity.CENTER);
-
- if (mText != null) {
- mTextView.setText(mText);
- Log.i("SimpleTextFragment", mText);
- }
- return mTextView;
- }
-
- public TextView getTextView() {
- return mTextView;
- }
-
- /**
- * Changes the text for this TextView, according to the resource ID provided.
- * @param stringId A resource ID representing the text content for this Fragment's TextView.
- */
- public void setText(int stringId) {
- getTextView().setText(getActivity().getString(stringId));
- }
-
- /**
- * Processes the arguments passed into this Fragment via setArguments method.
- * Currently the method only looks for text or a textID, nothing else.
- */
- public void processArguments() {
- // For most objects we'd handle the multiple possibilities for initialization variables
- // as multiple constructors. For Fragments, however, it's customary to use
- // setArguments / getArguments.
- if (getArguments() != null) {
- Bundle args = getArguments();
- if (args.containsKey(TEXT_KEY)) {
- mText = args.getString(TEXT_KEY);
- Log.d("Constructor", "Added Text.");
- } else if (args.containsKey(TEXT_ID_KEY)) {
- mTextId = args.getInt(TEXT_ID_KEY);
- mText = getString(mTextId);
- }
- }
- }
-} \ No newline at end of file
diff --git a/samples/browseable/Notifications/Application/AndroidManifest.xml b/samples/browseable/Notifications/Application/AndroidManifest.xml
index 6a17ad8c3..4b0a9b3a9 100644
--- a/samples/browseable/Notifications/Application/AndroidManifest.xml
+++ b/samples/browseable/Notifications/Application/AndroidManifest.xml
@@ -18,7 +18,7 @@
package="com.example.android.support.wearable.notifications" >
<uses-sdk android:minSdkVersion="18"
- android:targetSdkVersion="23" />
+ android:targetSdkVersion="25" />
<uses-permission android:name="android.permission.VIBRATE" />
diff --git a/samples/browseable/Notifications/Application/res/values/base-strings.xml b/samples/browseable/Notifications/Application/res/values/base-strings.xml
index 9ab282f7e..c5ef0694c 100644
--- a/samples/browseable/Notifications/Application/res/values/base-strings.xml
+++ b/samples/browseable/Notifications/Application/res/values/base-strings.xml
@@ -16,7 +16,7 @@
-->
<resources>
- <string name="app_name">Wearable Notifications</string>
+ <string name="app_name">Notifications</string>
<string name="intro_message">
<![CDATA[
diff --git a/samples/browseable/Notifications/Wearable/AndroidManifest.xml b/samples/browseable/Notifications/Wearable/AndroidManifest.xml
index a446fd9bb..0bce3ea94 100644
--- a/samples/browseable/Notifications/Wearable/AndroidManifest.xml
+++ b/samples/browseable/Notifications/Wearable/AndroidManifest.xml
@@ -17,8 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.support.wearable.notifications" >
- <uses-sdk android:minSdkVersion="20"
- android:targetSdkVersion="22" />
+ <uses-sdk android:minSdkVersion="22"
+ android:targetSdkVersion="25" />
<uses-feature android:name="android.hardware.type.watch" />
@@ -28,6 +28,10 @@
android:label="@string/app_name"
android:theme="@android:style/Theme.DeviceDefault.Light" >
+ <meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="false" />
+
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
diff --git a/samples/browseable/Notifications/_index.jd b/samples/browseable/Notifications/_index.jd
index e2bfa36b3..50d2020fb 100644
--- a/samples/browseable/Notifications/_index.jd
+++ b/samples/browseable/Notifications/_index.jd
@@ -1,5 +1,5 @@
-page.tags="Wearable Notifications"
+page.tags="Notifications"
sample.group=Wearable
@jd:body
diff --git a/samples/browseable/PdfRendererBasic/src/com.example.android.pdfrendererbasic/PdfRendererBasicFragment.java b/samples/browseable/PdfRendererBasic/src/com.example.android.pdfrendererbasic/PdfRendererBasicFragment.java
index e413c6599..20b0a7f45 100644
--- a/samples/browseable/PdfRendererBasic/src/com.example.android.pdfrendererbasic/PdfRendererBasicFragment.java
+++ b/samples/browseable/PdfRendererBasic/src/com.example.android.pdfrendererbasic/PdfRendererBasicFragment.java
@@ -30,7 +30,10 @@ import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
/**
* This fragment has a big {@ImageView} that shows PDF pages, and 2 {@link android.widget.Button}s to move between
@@ -44,6 +47,11 @@ public class PdfRendererBasicFragment extends Fragment implements View.OnClickLi
private static final String STATE_CURRENT_PAGE_INDEX = "current_page_index";
/**
+ * The filename of the PDF.
+ */
+ private static final String FILENAME = "sample.pdf";
+
+ /**
* File descriptor of the PDF.
*/
private ParcelFileDescriptor mFileDescriptor;
@@ -136,7 +144,21 @@ public class PdfRendererBasicFragment extends Fragment implements View.OnClickLi
*/
private void openRenderer(Context context) throws IOException {
// In this sample, we read a PDF from the assets directory.
- mFileDescriptor = context.getAssets().openFd("sample.pdf").getParcelFileDescriptor();
+ File file = new File(context.getCacheDir(), FILENAME);
+ if (!file.exists()) {
+ // Since PdfRenderer cannot handle the compressed asset file directly, we copy it into
+ // the cache directory.
+ InputStream asset = context.getAssets().open(FILENAME);
+ FileOutputStream output = new FileOutputStream(file);
+ final byte[] buffer = new byte[1024];
+ int size;
+ while ((size = asset.read(buffer)) != -1) {
+ output.write(buffer, 0, size);
+ }
+ asset.close();
+ output.close();
+ }
+ mFileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
// This is the PdfRenderer we use to render the PDF.
mPdfRenderer = new PdfRenderer(mFileDescriptor);
}
diff --git a/samples/browseable/PermissionRequest/res/values/strings.xml b/samples/browseable/PermissionRequest/res/values/strings.xml
index c3e5574dc..248876601 100644
--- a/samples/browseable/PermissionRequest/res/values/strings.xml
+++ b/samples/browseable/PermissionRequest/res/values/strings.xml
@@ -15,6 +15,7 @@
limitations under the License.
-->
<resources>
+ <string name="permission_message">This sample app uses camera.</string>
<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>
diff --git a/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/ConfirmationDialogFragment.java b/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/ConfirmationDialogFragment.java
index 7dae56efd..ca173b424 100644
--- a/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/ConfirmationDialogFragment.java
+++ b/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/ConfirmationDialogFragment.java
@@ -13,12 +13,14 @@
* 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.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.text.TextUtils;
@@ -32,7 +34,7 @@ public class ConfirmationDialogFragment extends DialogFragment {
/**
* Creates a new instance of ConfirmationDialogFragment.
*
- * @param resources The list of resources requested by PermissionRequeste.
+ * @param resources The list of resources requested by PermissionRequest.
* @return A new instance.
*/
public static ConfirmationDialogFragment newInstance(String[] resources) {
@@ -43,21 +45,22 @@ public class ConfirmationDialogFragment extends DialogFragment {
return fragment;
}
+ @NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- String[] resources = getArguments().getStringArray(ARG_RESOURCES);
+ final 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);
+ ((Listener) getParentFragment()).onConfirmation(false, resources);
}
})
.setPositiveButton(R.string.allow, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- ((Listener) getParentFragment()).onConfirmation(true);
+ ((Listener) getParentFragment()).onConfirmation(true, resources);
}
})
.create();
@@ -66,14 +69,15 @@ public class ConfirmationDialogFragment extends DialogFragment {
/**
* Callback for the user's response.
*/
- public interface Listener {
+ interface Listener {
/**
- * Called when the PermissoinRequest is allowed or denied by the user.
+ * Called when the PermissionRequest is allowed or denied by the user.
*
- * @param allowed True if the user allowed the request.
+ * @param allowed True if the user allowed the request.
+ * @param resources The resources to be granted.
*/
- public void onConfirmation(boolean allowed);
+ void onConfirmation(boolean allowed, String[] resources);
}
}
diff --git a/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/MessageDialogFragment.java b/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/MessageDialogFragment.java
new file mode 100644
index 000000000..31d0bcbf7
--- /dev/null
+++ b/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/MessageDialogFragment.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 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.annotation.NonNull;
+import android.support.annotation.StringRes;
+import android.support.v4.app.DialogFragment;
+
+/**
+ * Shows a dialog with a brief message.
+ */
+public class MessageDialogFragment extends DialogFragment {
+
+ private static final String ARG_MESSAGE_RES_ID = "message_res_id";
+
+ public static MessageDialogFragment newInstance(@StringRes int message) {
+ MessageDialogFragment fragment = new MessageDialogFragment();
+ Bundle args = new Bundle();
+ args.putInt(ARG_MESSAGE_RES_ID, message);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ return new AlertDialog.Builder(getContext())
+ .setMessage(getArguments().getInt(ARG_MESSAGE_RES_ID))
+ .setCancelable(false)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ((Listener) getParentFragment()).onOkClicked();
+ }
+ })
+ .create();
+ }
+
+ interface Listener {
+ void onOkClicked();
+ }
+
+}
diff --git a/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/PermissionRequestFragment.java b/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/PermissionRequestFragment.java
index 44f1d6ec5..418c90d34 100644
--- a/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/PermissionRequestFragment.java
+++ b/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/PermissionRequestFragment.java
@@ -16,12 +16,15 @@
package com.example.android.permissionrequest;
+import android.Manifest;
import android.annotation.SuppressLint;
+import android.content.pm.PackageManager;
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.support.v4.content.ContextCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -37,12 +40,14 @@ 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 {
+ implements ConfirmationDialogFragment.Listener, MessageDialogFragment.Listener {
private static final String TAG = PermissionRequestFragment.class.getSimpleName();
private static final String FRAGMENT_DIALOG = "dialog";
+ private static final int REQUEST_CAMERA_PERMISSION = 1;
+
/**
* 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.
@@ -67,7 +72,7 @@ public class PermissionRequestFragment extends Fragment
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
+ @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_permission_request, container, false);
}
@@ -85,7 +90,14 @@ public class PermissionRequestFragment extends Fragment
final int port = 8080;
mWebServer = new SimpleWebServer(port, getResources().getAssets());
mWebServer.start();
- mWebView.loadUrl("http://localhost:" + port + "/sample.html");
+ // This is for runtime permission on Marshmallow and above; It is not directly related to
+ // PermissionRequest API.
+ if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
+ != PackageManager.PERMISSION_GRANTED) {
+ requestCameraPermission();
+ } else {
+ mWebView.loadUrl("http://localhost:" + port + "/sample.html");
+ }
}
@Override
@@ -94,6 +106,32 @@ public class PermissionRequestFragment extends Fragment
super.onPause();
}
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ // This is for runtime permission on Marshmallow and above; It is not directly related to
+ // PermissionRequest API.
+ if (requestCode == REQUEST_CAMERA_PERMISSION) {
+ if (permissions.length != 1 || grantResults.length != 1 ||
+ grantResults[0] != PackageManager.PERMISSION_GRANTED) {
+ Log.e(TAG, "Camera permission not granted.");
+ } else if (mWebView != null && mWebServer != null) {
+ mWebView.loadUrl("http://localhost:" + mWebServer.getPort() + "/sample.html");
+ }
+ } else {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+ }
+
+ private void requestCameraPermission() {
+ if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
+ MessageDialogFragment.newInstance(R.string.permission_message)
+ .show(getChildFragmentManager(), FRAGMENT_DIALOG);
+ } else {
+ requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
+ }
+ }
+
@SuppressLint("SetJavaScriptEnabled")
private static void configureWebSettings(WebSettings settings) {
settings.setJavaScriptEnabled(true);
@@ -110,8 +148,16 @@ public class PermissionRequestFragment extends Fragment
public void onPermissionRequest(PermissionRequest request) {
Log.i(TAG, "onPermissionRequest");
mPermissionRequest = request;
- ConfirmationDialogFragment.newInstance(request.getResources())
- .show(getChildFragmentManager(), FRAGMENT_DIALOG);
+ final String[] requestedResources = request.getResources();
+ for (String r : requestedResources) {
+ if (r.equals(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) {
+ // In this sample, we only accept video capture request.
+ ConfirmationDialogFragment
+ .newInstance(new String[]{PermissionRequest.RESOURCE_VIDEO_CAPTURE})
+ .show(getChildFragmentManager(), FRAGMENT_DIALOG);
+ break;
+ }
+ }
}
// This method is called when the permission request is canceled by the web content.
@@ -155,9 +201,14 @@ public class PermissionRequestFragment extends Fragment
};
@Override
- public void onConfirmation(boolean allowed) {
+ public void onOkClicked() {
+ requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
+ }
+
+ @Override
+ public void onConfirmation(boolean allowed, String[] resources) {
if (allowed) {
- mPermissionRequest.grant(mPermissionRequest.getResources());
+ mPermissionRequest.grant(resources);
Log.d(TAG, "Permission granted.");
} else {
mPermissionRequest.deny();
@@ -174,7 +225,7 @@ public class PermissionRequestFragment extends Fragment
* For testing.
*/
public interface ConsoleMonitor {
- public void onConsoleMessage(ConsoleMessage message);
+ void onConsoleMessage(ConsoleMessage message);
}
}
diff --git a/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/SimpleWebServer.java b/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/SimpleWebServer.java
index 36b7c4693..b02275af5 100644
--- a/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/SimpleWebServer.java
+++ b/samples/browseable/PermissionRequest/src/com.example.android.permissionrequest/SimpleWebServer.java
@@ -90,6 +90,10 @@ public class SimpleWebServer implements Runnable {
}
}
+ public int getPort() {
+ return mPort;
+ }
+
@Override
public void run() {
try {
diff --git a/samples/browseable/RepeatingAlarm/res/menu/main.xml b/samples/browseable/RepeatingAlarm/res/menu/main.xml
index 2c3515dd4..498f2c60e 100644
--- a/samples/browseable/RepeatingAlarm/res/menu/main.xml
+++ b/samples/browseable/RepeatingAlarm/res/menu/main.xml
@@ -14,8 +14,9 @@
limitations under the License.
-->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/sample_action"
- android:showAsAction="ifRoom|withText"
+ app:showAsAction="ifRoom|withText"
android:title="@string/sample_action" />
</menu>
diff --git a/samples/browseable/RuntimePermissionsWear/Wearable/AndroidManifest.xml b/samples/browseable/RuntimePermissionsWear/Wearable/AndroidManifest.xml
index e654253fc..385d3ce19 100644
--- a/samples/browseable/RuntimePermissionsWear/Wearable/AndroidManifest.xml
+++ b/samples/browseable/RuntimePermissionsWear/Wearable/AndroidManifest.xml
@@ -31,6 +31,10 @@
android:theme="@android:style/Theme.DeviceDefault" >
<meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="false" />
+
+ <meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/AndroidManifest.xml b/samples/browseable/ShareActionProvider/AndroidManifest.xml
index 18dfc27fd..95283386f 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/AndroidManifest.xml
+++ b/samples/browseable/ShareActionProvider/AndroidManifest.xml
@@ -16,14 +16,12 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.actionbarcompat.shareactionprovider"
+ package="com.example.android.shareactionprovider"
android:versionCode="1"
android:versionName="1.0">
- <!--
- ActionBarCompat provides an Action Bar from API v7 onwards
- -->
- <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+ <permission android:name="com.example.android.shareactionprovider.ASSET_ACCESS"
+ android:protectionLevel="signature" />
<application
android:icon="@drawable/ic_launcher"
@@ -41,12 +39,14 @@
</activity>
<!-- ContentProvider which serves files from this application's asset folder -->
+ <!-- Allow the access to only the apps having the same signature for security -->
<provider
android:name=".content.AssetProvider"
- android:authorities="com.example.android.actionbarcompat.shareactionprovider"
+ android:authorities="com.example.android.shareactionprovider"
android:grantUriPermissions="true"
- android:exported="true" />
+ android:exported="true"
+ android:permission="com.example.android.shareactionprovider.ASSET_ACCESS" />
</application>
-</manifest> \ No newline at end of file
+</manifest>
diff --git a/samples/browseable/ShareActionProvider/_index.jd b/samples/browseable/ShareActionProvider/_index.jd
new file mode 100644
index 000000000..ae52e4ec8
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/_index.jd
@@ -0,0 +1,10 @@
+
+page.tags="ShareActionProvider"
+sample.group=UI
+@jd:body
+
+<p>
+
+ This sample shows you how a provide a context-sensitive ShareActionProvider.
+
+ </p>
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-hdpi/ic_launcher.png b/samples/browseable/ShareActionProvider/res/drawable-hdpi/ic_launcher.png
index 48db73f18..48db73f18 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-hdpi/ic_launcher.png
+++ b/samples/browseable/ShareActionProvider/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-hdpi/tile.9.png b/samples/browseable/ShareActionProvider/res/drawable-hdpi/tile.9.png
index 135862883..135862883 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-hdpi/tile.9.png
+++ b/samples/browseable/ShareActionProvider/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-mdpi/ic_launcher.png b/samples/browseable/ShareActionProvider/res/drawable-mdpi/ic_launcher.png
index 674b1eee3..674b1eee3 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-mdpi/ic_launcher.png
+++ b/samples/browseable/ShareActionProvider/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/ShareActionProvider/res/drawable-xhdpi/ic_launcher.png
index e76105d9f..e76105d9f 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-xhdpi/ic_launcher.png
+++ b/samples/browseable/ShareActionProvider/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/ShareActionProvider/res/drawable-xxhdpi/ic_launcher.png
index 67605d802..67605d802 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-xxhdpi/ic_launcher.png
+++ b/samples/browseable/ShareActionProvider/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/item_image.xml b/samples/browseable/ShareActionProvider/res/layout/item_image.xml
index f7940e75e..f7940e75e 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/item_image.xml
+++ b/samples/browseable/ShareActionProvider/res/layout/item_image.xml
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/item_text.xml b/samples/browseable/ShareActionProvider/res/layout/item_text.xml
index 00c6a387d..00c6a387d 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/item_text.xml
+++ b/samples/browseable/ShareActionProvider/res/layout/item_text.xml
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/sample_main.xml b/samples/browseable/ShareActionProvider/res/layout/sample_main.xml
index 902e8ab27..902e8ab27 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/sample_main.xml
+++ b/samples/browseable/ShareActionProvider/res/layout/sample_main.xml
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/menu/main_menu.xml b/samples/browseable/ShareActionProvider/res/menu/main_menu.xml
index acd213417..4b8526736 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/menu/main_menu.xml
+++ b/samples/browseable/ShareActionProvider/res/menu/main_menu.xml
@@ -16,8 +16,7 @@
-->
<!--
- As we're using ActionBarCompat, any action item attributes come from ActionBarCompat's XML
- namespace instead of the android namespace. Here we've added a new support namespace added to
+ Here we've added a new support namespace added to
the menu element allowing us to use the 'showAsAction' attribute in a backwards compatible way.
Any other action item attributes used should be referenced from this namespace too
(actionProviderClass, actionViewClass, actionLayout).
@@ -26,7 +25,7 @@
xmlns:support="http://schemas.android.com/apk/res-auto">
<!--
- To use ShareActionProvider provided by ActionBarCompat, we reference the class by set the
+ To use ShareActionProvider, we reference the class by set the
support:actionProviderClass attribute with the full class name of ShareActionProvider.
-->
<item
@@ -35,4 +34,4 @@
support:actionProviderClass="android.support.v7.widget.ShareActionProvider"
support:showAsAction="always" />
-</menu> \ No newline at end of file
+</menu>
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values-sw600dp/template-dimens.xml b/samples/browseable/ShareActionProvider/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values-sw600dp/template-dimens.xml
+++ b/samples/browseable/ShareActionProvider/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values-sw600dp/template-styles.xml b/samples/browseable/ShareActionProvider/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values-sw600dp/template-styles.xml
+++ b/samples/browseable/ShareActionProvider/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values-v11/template-styles.xml b/samples/browseable/ShareActionProvider/res/values-v11/template-styles.xml
index 8c1ea66f2..8c1ea66f2 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values-v11/template-styles.xml
+++ b/samples/browseable/ShareActionProvider/res/values-v11/template-styles.xml
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values-v21/base-colors.xml b/samples/browseable/ShareActionProvider/res/values-v21/base-colors.xml
index 8b6ec3f85..8b6ec3f85 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values-v21/base-colors.xml
+++ b/samples/browseable/ShareActionProvider/res/values-v21/base-colors.xml
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values-v21/base-template-styles.xml b/samples/browseable/ShareActionProvider/res/values-v21/base-template-styles.xml
index c778e4f98..c778e4f98 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values-v21/base-template-styles.xml
+++ b/samples/browseable/ShareActionProvider/res/values-v21/base-template-styles.xml
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values/base-strings.xml b/samples/browseable/ShareActionProvider/res/values/base-strings.xml
index 21d17e4f5..ab5e2fbdc 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values/base-strings.xml
+++ b/samples/browseable/ShareActionProvider/res/values/base-strings.xml
@@ -16,13 +16,12 @@
-->
<resources>
- <string name="app_name">ActionBarCompat-ShareActionProvider</string>
+ <string name="app_name">ShareActionProvider</string>
<string name="intro_message">
<![CDATA[
- This sample shows you how a provide a context-sensitive ShareActionProvider with
- ActionBarCompat, backwards compatible to API v7.
+ This sample shows you how a provide a context-sensitive ShareActionProvider.
]]>
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values/strings.xml b/samples/browseable/ShareActionProvider/res/values/strings.xml
index 298596f04..298596f04 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values/strings.xml
+++ b/samples/browseable/ShareActionProvider/res/values/strings.xml
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values/template-dimens.xml b/samples/browseable/ShareActionProvider/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values/template-dimens.xml
+++ b/samples/browseable/ShareActionProvider/res/values/template-dimens.xml
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values/template-styles.xml b/samples/browseable/ShareActionProvider/res/values/template-styles.xml
index 6e7d593dd..6e7d593dd 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/res/values/template-styles.xml
+++ b/samples/browseable/ShareActionProvider/res/values/template-styles.xml
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/MainActivity.java b/samples/browseable/ShareActionProvider/src/com.example.android.shareactionprovider/MainActivity.java
index 545764cad..3ac28ea62 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/MainActivity.java
+++ b/samples/browseable/ShareActionProvider/src/com.example.android.shareactionprovider/MainActivity.java
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-package com.example.android.actionbarcompat.shareactionprovider;
+package com.example.android.shareactionprovider;
+
+import com.example.android.shareactionprovider.content.ContentItem;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.ShareActionProvider;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -31,8 +33,6 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
-import com.example.android.actionbarcompat.shareactionprovider.content.ContentItem;
-
import java.util.ArrayList;
/**
@@ -43,10 +43,8 @@ import java.util.ArrayList;
* text. When a new item is selected in the ViewPager, the ShareActionProvider is updated with
* a share intent specific to that content.
* <p>
- * This Activity extends from {@link ActionBarActivity}, which provides all of the function
- * necessary to display a compatible Action Bar on devices running Android v2.1+.
*/
-public class MainActivity extends ActionBarActivity {
+public class MainActivity extends AppCompatActivity {
// The items to be displayed in the ViewPager
private final ArrayList<ContentItem> mItems = getSampleContent();
@@ -65,7 +63,7 @@ public class MainActivity extends ActionBarActivity {
ViewPager vp = (ViewPager) findViewById(R.id.viewpager);
// Set an OnPageChangeListener so we are notified when a new item is selected
- vp.setOnPageChangeListener(mOnPageChangeListener);
+ vp.addOnPageChangeListener(mOnPageChangeListener);
// Finally set the adapter so the ViewPager can display items
vp.setAdapter(mPagerAdapter);
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/AssetProvider.java b/samples/browseable/ShareActionProvider/src/com.example.android.shareactionprovider/content/AssetProvider.java
index b60f7d78b..21e3ab2a8 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/AssetProvider.java
+++ b/samples/browseable/ShareActionProvider/src/com.example.android.shareactionprovider/content/AssetProvider.java
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-package com.example.android.actionbarcompat.shareactionprovider.content;
+package com.example.android.shareactionprovider.content;
import android.content.ContentProvider;
import android.content.ContentValues;
+import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.net.Uri;
+import android.support.annotation.NonNull;
import android.text.TextUtils;
import java.io.FileNotFoundException;
@@ -41,38 +43,41 @@ public class AssetProvider extends ContentProvider {
}
@Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
+ public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
// Do not support delete requests.
return 0;
}
@Override
- public String getType(Uri uri) {
+ public String getType(@NonNull Uri uri) {
// Do not support returning the data type
return null;
}
@Override
- public Uri insert(Uri uri, ContentValues values) {
+ public Uri insert(@NonNull Uri uri, ContentValues values) {
// Do not support insert requests.
return null;
}
@Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ public Cursor query(@NonNull Uri uri, String[] projection, String selection,
+ String[] selectionArgs,
String sortOrder) {
// Do not support query requests.
return null;
}
@Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ public int update(@NonNull Uri uri, ContentValues values, String selection,
+ String[] selectionArgs) {
// Do not support update requests.
return 0;
}
@Override
- public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
+ public AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode)
+ throws FileNotFoundException {
// The asset file name should be the last path segment
final String assetName = uri.getLastPathSegment();
@@ -83,7 +88,11 @@ public class AssetProvider extends ContentProvider {
try {
// Try and return a file descriptor for the given asset name
- AssetManager am = getContext().getAssets();
+ Context context = getContext();
+ if (context == null) {
+ return super.openAssetFile(uri, mode);
+ }
+ AssetManager am = context.getAssets();
return am.openFd(assetName);
} catch (IOException e) {
e.printStackTrace();
diff --git a/samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/ContentItem.java b/samples/browseable/ShareActionProvider/src/com.example.android.shareactionprovider/content/ContentItem.java
index 756a9e66d..5806088b7 100644
--- a/samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/ContentItem.java
+++ b/samples/browseable/ShareActionProvider/src/com.example.android.shareactionprovider/content/ContentItem.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.example.android.actionbarcompat.shareactionprovider.content;
+package com.example.android.shareactionprovider.content;
import android.content.Context;
import android.content.Intent;
@@ -33,7 +33,7 @@ public class ContentItem {
public final int contentType;
public final int contentResourceId;
- public final String contentAssetFilePath;
+ private final String mContentAssetFilePath;
/**
* Creates a ContentItem with the specified type, referencing a resource id.
@@ -44,7 +44,7 @@ public class ContentItem {
public ContentItem(int type, int resourceId) {
contentType = type;
contentResourceId = resourceId;
- contentAssetFilePath = null;
+ mContentAssetFilePath = null;
}
/**
@@ -55,7 +55,7 @@ public class ContentItem {
*/
public ContentItem(int type, String assetFilePath) {
contentType = type;
- contentAssetFilePath = assetFilePath;
+ mContentAssetFilePath = assetFilePath;
contentResourceId = 0;
}
@@ -63,9 +63,9 @@ public class ContentItem {
* @return Uri to the content
*/
public Uri getContentUri() {
- if (!TextUtils.isEmpty(contentAssetFilePath)) {
+ if (!TextUtils.isEmpty(mContentAssetFilePath)) {
// If this content has an asset, then return a AssetProvider Uri
- return Uri.parse("content://" + AssetProvider.CONTENT_URI + "/" + contentAssetFilePath);
+ return Uri.parse("content://" + AssetProvider.CONTENT_URI + "/" + mContentAssetFilePath);
} else {
return null;
}
diff --git a/samples/browseable/SpeedTracker/Application/AndroidManifest.xml b/samples/browseable/SpeedTracker/Application/AndroidManifest.xml
index debd11d6f..bf86a10cc 100644
--- a/samples/browseable/SpeedTracker/Application/AndroidManifest.xml
+++ b/samples/browseable/SpeedTracker/Application/AndroidManifest.xml
@@ -5,7 +5,7 @@
<uses-sdk
android:minSdkVersion="18"
- android:targetSdkVersion="23" />
+ android:targetSdkVersion="25" />
<!-- BEGIN_INCLUDE(manifest) -->
diff --git a/samples/browseable/SpeedTracker/Application/res/layout/main_activity.xml b/samples/browseable/SpeedTracker/Application/res/layout/main_activity.xml
index 17a8f6a9d..ef2480a61 100644
--- a/samples/browseable/SpeedTracker/Application/res/layout/main_activity.xml
+++ b/samples/browseable/SpeedTracker/Application/res/layout/main_activity.xml
@@ -43,10 +43,10 @@
</RelativeLayout>
<fragment
+ class="com.google.android.gms.maps.SupportMapFragment"
android:id="@+id/map"
android:layout_below="@+id/top_container"
- android:layout_width="fill_parent"
- android:layout_height="match_parent"
- android:name="com.google.android.gms.maps.MapFragment"/>
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/samples/browseable/SpeedTracker/Application/res/values/base-strings.xml b/samples/browseable/SpeedTracker/Application/res/values/base-strings.xml
index 61f103ceb..b5e0a236b 100644
--- a/samples/browseable/SpeedTracker/Application/res/values/base-strings.xml
+++ b/samples/browseable/SpeedTracker/Application/res/values/base-strings.xml
@@ -16,14 +16,13 @@
-->
<resources>
- <string name="app_name">Speed Tracker</string>
+ <string name="app_name">SpeedTracker</string>
<string name="intro_message">
<![CDATA[
This sample uses the FusedLocation APIs of Google Play Services
-on those devices that have a hardware GPS built in. In those
-cases, this sample provides a simple screen that shows the
+to gather location and speed. The sample provides a simple screen that shows the
current speed of the device on the watch. User can set a speed
limit and if the speed approaches that limit, it changes the
color to yellow and if it exceeds the limit, it turns red. User
diff --git a/samples/browseable/SpeedTracker/Application/src/com.example.android.wearable.speedtracker/PhoneMainActivity.java b/samples/browseable/SpeedTracker/Application/src/com.example.android.wearable.speedtracker/PhoneMainActivity.java
index c645bdd62..b915d26d0 100644
--- a/samples/browseable/SpeedTracker/Application/src/com.example.android.wearable.speedtracker/PhoneMainActivity.java
+++ b/samples/browseable/SpeedTracker/Application/src/com.example.android.wearable.speedtracker/PhoneMainActivity.java
@@ -18,7 +18,8 @@ package com.example.android.wearable.speedtracker;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
-import com.google.android.gms.maps.MapFragment;
+import com.google.android.gms.maps.SupportMapFragment;
+import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.PolylineOptions;
@@ -46,19 +47,21 @@ import java.util.List;
* deleted.
*/
public class PhoneMainActivity extends AppCompatActivity implements
- DatePickerDialog.OnDateSetListener {
+ DatePickerDialog.OnDateSetListener, OnMapReadyCallback {
private static final String TAG = "PhoneMainActivity";
private static final int BOUNDING_BOX_PADDING_PX = 50;
private TextView mSelectedDateText;
private GoogleMap mMap;
+ private SupportMapFragment mMapFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
mSelectedDateText = (TextView) findViewById(R.id.selected_date);
- mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
+ mMapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
+ mMapFragment.getMapAsync(this);
}
public void onClick(View view) {
@@ -132,4 +135,9 @@ public class PhoneMainActivity extends AppCompatActivity implements
}.execute(calendar);
}
+
+ @Override
+ public void onMapReady(GoogleMap googleMap) {
+ mMap = googleMap;
+ }
}
diff --git a/samples/browseable/SpeedTracker/Wearable/AndroidManifest.xml b/samples/browseable/SpeedTracker/Wearable/AndroidManifest.xml
index e120686e5..feb2b813f 100644
--- a/samples/browseable/SpeedTracker/Wearable/AndroidManifest.xml
+++ b/samples/browseable/SpeedTracker/Wearable/AndroidManifest.xml
@@ -24,7 +24,7 @@
<uses-sdk
android:minSdkVersion="20"
- android:targetSdkVersion="23" />
+ android:targetSdkVersion="25" />
<application
android:allowBackup="true"
@@ -32,6 +32,10 @@
android:label="@string/app_name"
android:theme="@android:style/Theme.DeviceDefault">
+ <meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="false" />
+
<!--If you want your app to run on pre-22, then set required to false -->
<uses-library android:name="com.google.android.wearable" android:required="false" />
diff --git a/samples/browseable/SpeedTracker/Wearable/src/com.example.android.wearable.speedtracker/WearableMainActivity.java b/samples/browseable/SpeedTracker/Wearable/src/com.example.android.wearable.speedtracker/WearableMainActivity.java
index 66550c6c5..20ded86fa 100644
--- a/samples/browseable/SpeedTracker/Wearable/src/com.example.android.wearable.speedtracker/WearableMainActivity.java
+++ b/samples/browseable/SpeedTracker/Wearable/src/com.example.android.wearable.speedtracker/WearableMainActivity.java
@@ -29,6 +29,7 @@ import com.google.android.gms.wearable.PutDataRequest;
import com.google.android.gms.wearable.Wearable;
import android.Manifest;
+import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
@@ -326,6 +327,7 @@ public class WearableMainActivity extends WearableActivity implements
}
}
+ @SuppressLint("MissingPermission")
@Override
public void onConnected(Bundle bundle) {
diff --git a/samples/browseable/SpeedTracker/_index.jd b/samples/browseable/SpeedTracker/_index.jd
index e87095247..398e9d4a0 100644
--- a/samples/browseable/SpeedTracker/_index.jd
+++ b/samples/browseable/SpeedTracker/_index.jd
@@ -1,13 +1,12 @@
-page.tags="Speed Tracker"
+page.tags="SpeedTracker"
sample.group=Wearable
@jd:body
<p>
This sample uses the FusedLocation APIs of Google Play Services
-on those devices that have a hardware GPS built in. In those
-cases, this sample provides a simple screen that shows the
+to gather location and speed. The sample provides a simple screen that shows the
current speed of the device on the watch. User can set a speed
limit and if the speed approaches that limit, it changes the
color to yellow and if it exceeds the limit, it turns red. User
diff --git a/samples/browseable/StorageClient/res/menu/main.xml b/samples/browseable/StorageClient/res/menu/main.xml
index 2c3515dd4..498f2c60e 100644
--- a/samples/browseable/StorageClient/res/menu/main.xml
+++ b/samples/browseable/StorageClient/res/menu/main.xml
@@ -14,8 +14,9 @@
limitations under the License.
-->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/sample_action"
- android:showAsAction="ifRoom|withText"
+ app:showAsAction="ifRoom|withText"
android:title="@string/sample_action" />
</menu>
diff --git a/samples/browseable/StorageProvider/res/menu/main.xml b/samples/browseable/StorageProvider/res/menu/main.xml
index 2c3515dd4..498f2c60e 100644
--- a/samples/browseable/StorageProvider/res/menu/main.xml
+++ b/samples/browseable/StorageProvider/res/menu/main.xml
@@ -14,8 +14,9 @@
limitations under the License.
-->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/sample_action"
- android:showAsAction="ifRoom|withText"
+ app:showAsAction="ifRoom|withText"
android:title="@string/sample_action" />
</menu>
diff --git a/samples/browseable/SwipeRefreshMultipleViews/src/com.example.android.swiperefreshmultipleviews/SwipeRefreshMultipleViewsFragment.java b/samples/browseable/SwipeRefreshMultipleViews/src/com.example.android.swiperefreshmultipleviews/SwipeRefreshMultipleViewsFragment.java
index e2b83d355..7bb29c847 100644
--- a/samples/browseable/SwipeRefreshMultipleViews/src/com.example.android.swiperefreshmultipleviews/SwipeRefreshMultipleViewsFragment.java
+++ b/samples/browseable/SwipeRefreshMultipleViews/src/com.example.android.swiperefreshmultipleviews/SwipeRefreshMultipleViewsFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 The Android Open Source Project
+ * Copyright 2016 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.
@@ -87,22 +87,17 @@ public class SwipeRefreshMultipleViewsFragment extends Fragment {
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_sample, container, false);
- // Retrieve the SwipeRefreshLayout and GridView instances
mSwipeRefreshLayout = (MultiSwipeRefreshLayout) view.findViewById(R.id.swiperefresh);
// BEGIN_INCLUDE (change_colors)
// Set the color scheme of the SwipeRefreshLayout by providing 4 color resource ids
- mSwipeRefreshLayout.setColorScheme(
+ mSwipeRefreshLayout.setColorSchemeResources(
R.color.swipe_color_1, R.color.swipe_color_2,
R.color.swipe_color_3, R.color.swipe_color_4);
// END_INCLUDE (change_colors)
- // Retrieve the GridView
mGridView = (GridView) view.findViewById(android.R.id.list);
-
- // Retrieve the empty view
mEmptyView = view.findViewById(android.R.id.empty);
-
return view;
}
// END_INCLUDE (inflate_view)
@@ -116,7 +111,7 @@ public class SwipeRefreshMultipleViewsFragment extends Fragment {
* Create an ArrayAdapter to contain the data for the GridView. Each item in the GridView
* uses the system-defined simple_list_item_1 layout that contains one TextView. Initially
*/
- mListAdapter = new ArrayAdapter<String>(
+ mListAdapter = new ArrayAdapter<>(
getActivity(),
android.R.layout.simple_list_item_1,
android.R.id.text1);
diff --git a/samples/browseable/SynchronizedNotifications/Wearable/AndroidManifest.xml b/samples/browseable/SynchronizedNotifications/Wearable/AndroidManifest.xml
index 2bc2fd860..86e8f7a9c 100644
--- a/samples/browseable/SynchronizedNotifications/Wearable/AndroidManifest.xml
+++ b/samples/browseable/SynchronizedNotifications/Wearable/AndroidManifest.xml
@@ -20,7 +20,7 @@
package="com.example.android.wearable.synchronizednotifications">
<uses-sdk android:minSdkVersion="20"
- android:targetSdkVersion="22" />
+ android:targetSdkVersion="25" />
<uses-feature android:name="android.hardware.type.watch" />
@@ -29,6 +29,11 @@
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.DeviceDefault.Light" >
+
+ <meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="false" />
+
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<activity
diff --git a/samples/browseable/WatchFace/Application/AndroidManifest.xml b/samples/browseable/WatchFace/Application/AndroidManifest.xml
index d946cdb0f..4092097e0 100644
--- a/samples/browseable/WatchFace/Application/AndroidManifest.xml
+++ b/samples/browseable/WatchFace/Application/AndroidManifest.xml
@@ -18,7 +18,7 @@
package="com.example.android.wearable.watchface" >
<uses-sdk android:minSdkVersion="18"
- android:targetSdkVersion="23" />
+ android:targetSdkVersion="25" />
<!-- Permissions required by the wearable app -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
diff --git a/samples/browseable/WatchFace/Application/res/values/base-strings.xml b/samples/browseable/WatchFace/Application/res/values/base-strings.xml
index 49e710098..be177c52f 100644
--- a/samples/browseable/WatchFace/Application/res/values/base-strings.xml
+++ b/samples/browseable/WatchFace/Application/res/values/base-strings.xml
@@ -20,17 +20,32 @@
<string name="intro_message">
<![CDATA[
-
+
This sample demonstrates how to create watch faces for android wear and includes a phone app
and a wearable app. The wearable app has a variety of watch faces including analog, digital,
opengl, calendar, steps, interactive, etc. It also includes a watch-side configuration example.
The phone app includes a phone-side configuration example.
-Additional note on Steps WatchFace Sample, if the user has not installed or setup the Google Fit app
-on their phone and their Wear device has not configured the Google Fit Wear App, then you may get
-zero steps until one of the two is setup. Please note, many Wear devices configure the Google Fit
-Wear App beforehand.
-
+Because watch face apps do not have a default Activity in their project, you will need to set your
+Configurations to "Do not launch Activity" for both the Wear and Application modules. If you are
+unsure how to do this, please review the "Run Starter project" section in the
+[Google Watch Face Code Lab][1].
+
+For the Fit Distance related watch face, authentication IS a requirement to request distance from
+Google Fit on Wear. Otherwise, distance will always come back as zero (or stay at whatever the
+distance was prior to you de-authorizing the watch face).
+
+To authenticate and communicate with Google Fit, you must create a project in the Google Developers
+Console, activate the Fitness API, create an OAuth 2.0 client ID, and register the public
+certificate from your signed APK. More details can be found [here][2].
+
+If the user has not installed or setup the Google Fit app on their phone and their Wear device has
+not configured the Google Fit Wear App, then you may get zero steps until one of the two is setup.
+Please note, many Wear devices configure the Google Fit Wear App beforehand.
+
+[1]: https://codelabs.developers.google.com/codelabs/watchface/index.html
+[2]: https://developers.google.com/fit/android/get-started#step_3_enable_the_fitness_api
+
]]>
</string>
diff --git a/samples/browseable/WatchFace/Wearable/AndroidManifest.xml b/samples/browseable/WatchFace/Wearable/AndroidManifest.xml
index 7dd5b69a9..09b914eb2 100644
--- a/samples/browseable/WatchFace/Wearable/AndroidManifest.xml
+++ b/samples/browseable/WatchFace/Wearable/AndroidManifest.xml
@@ -19,7 +19,7 @@
<uses-sdk
android:minSdkVersion="21"
- android:targetSdkVersion="23"/>
+ android:targetSdkVersion="25"/>
<uses-feature android:name="android.hardware.type.watch"/>
@@ -35,14 +35,19 @@
<!-- Location permission used by FitDistanceWatchFaceService -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
- <android:uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <android:uses-permission android:name="android.permission.READ_PHONE_STATE"/>
- <android:uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
+
+ <meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="true" />
+
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"/>
diff --git a/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/DigitalWatchFaceService.java b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/DigitalWatchFaceService.java
index 0a9eff2fe..f3f97fb55 100644
--- a/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/DigitalWatchFaceService.java
+++ b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/DigitalWatchFaceService.java
@@ -28,6 +28,7 @@ import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.support.v4.content.ContextCompat;
import android.support.wearable.watchface.CanvasWatchFaceService;
import android.support.wearable.watchface.WatchFaceService;
import android.support.wearable.watchface.WatchFaceStyle;
@@ -200,12 +201,15 @@ public class DigitalWatchFaceService extends CanvasWatchFaceService {
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(mInteractiveBackgroundColor);
- mDatePaint = createTextPaint(resources.getColor(R.color.digital_date));
+ mDatePaint = createTextPaint(
+ ContextCompat.getColor(getApplicationContext(), R.color.digital_date));
mHourPaint = createTextPaint(mInteractiveHourDigitsColor, BOLD_TYPEFACE);
mMinutePaint = createTextPaint(mInteractiveMinuteDigitsColor);
mSecondPaint = createTextPaint(mInteractiveSecondDigitsColor);
- mAmPmPaint = createTextPaint(resources.getColor(R.color.digital_am_pm));
- mColonPaint = createTextPaint(resources.getColor(R.color.digital_colons));
+ mAmPmPaint = createTextPaint(
+ ContextCompat.getColor(getApplicationContext(), R.color.digital_am_pm));
+ mColonPaint = createTextPaint(
+ ContextCompat.getColor(getApplicationContext(), R.color.digital_colons));
mCalendar = Calendar.getInstance();
mDate = new Date();
diff --git a/samples/browseable/WatchFace/_index.jd b/samples/browseable/WatchFace/_index.jd
index 4367419fa..be2d1aa15 100644
--- a/samples/browseable/WatchFace/_index.jd
+++ b/samples/browseable/WatchFace/_index.jd
@@ -4,15 +4,30 @@ sample.group=Wearable
@jd:body
<p>
-
+
This sample demonstrates how to create watch faces for android wear and includes a phone app
and a wearable app. The wearable app has a variety of watch faces including analog, digital,
opengl, calendar, steps, interactive, etc. It also includes a watch-side configuration example.
The phone app includes a phone-side configuration example.
-Additional note on Steps WatchFace Sample, if the user has not installed or setup the Google Fit app
-on their phone and their Wear device has not configured the Google Fit Wear App, then you may get
-zero steps until one of the two is setup. Please note, many Wear devices configure the Google Fit
-Wear App beforehand.
-
+Because watch face apps do not have a default Activity in their project, you will need to set your
+Configurations to "Do not launch Activity" for both the Wear and Application modules. If you are
+unsure how to do this, please review the "Run Starter project" section in the
+[Google Watch Face Code Lab][1].
+
+For the Fit Distance related watch face, authentication IS a requirement to request distance from
+Google Fit on Wear. Otherwise, distance will always come back as zero (or stay at whatever the
+distance was prior to you de-authorizing the watch face).
+
+To authenticate and communicate with Google Fit, you must create a project in the Google Developers
+Console, activate the Fitness API, create an OAuth 2.0 client ID, and register the public
+certificate from your signed APK. More details can be found [here][2].
+
+If the user has not installed or setup the Google Fit app on their phone and their Wear device has
+not configured the Google Fit Wear App, then you may get zero steps until one of the two is setup.
+Please note, many Wear devices configure the Google Fit Wear App beforehand.
+
+[1]: https://codelabs.developers.google.com/codelabs/watchface/index.html
+[2]: https://developers.google.com/fit/android/get-started#step_3_enable_the_fitness_api
+
</p>
diff --git a/samples/browseable/WatchViewStub/AndroidManifest.xml b/samples/browseable/WatchViewStub/AndroidManifest.xml
index 774817bad..ce1dfc3c6 100644
--- a/samples/browseable/WatchViewStub/AndroidManifest.xml
+++ b/samples/browseable/WatchViewStub/AndroidManifest.xml
@@ -17,8 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.google.wearable.watchviewstub" >
- <uses-sdk android:minSdkVersion="20"
- android:targetSdkVersion="22" />
+ <uses-sdk android:minSdkVersion="22"
+ android:targetSdkVersion="25" />
<uses-feature android:name="android.hardware.type.watch" />
@@ -27,6 +27,11 @@
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.DeviceDefault">
+
+ <meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="true" />
+
<activity
android:name="com.example.android.google.wearable.watchviewstub.MainActivity"
android:label="@string/app_name">
diff --git a/samples/browseable/WearDrawers/AndroidManifest.xml b/samples/browseable/WearDrawers/AndroidManifest.xml
index eaf9dbdbf..fae56dce6 100644
--- a/samples/browseable/WearDrawers/AndroidManifest.xml
+++ b/samples/browseable/WearDrawers/AndroidManifest.xml
@@ -13,6 +13,10 @@
android:supportsRtl="true"
android:theme="@android:style/Theme.DeviceDefault">
+ <meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="true" />
+
<!--If you want your app to run on pre-22, then set required to false -->
<uses-library android:name="com.google.android.wearable" android:required="false" />
diff --git a/samples/browseable/WearDrawers/src/com.example.android.wearable.wear.weardrawers/MainActivity.java b/samples/browseable/WearDrawers/src/com.example.android.wearable.wear.weardrawers/MainActivity.java
index f2e00c056..4fc2f2f70 100644
--- a/samples/browseable/WearDrawers/src/com.example.android.wearable.wear.weardrawers/MainActivity.java
+++ b/samples/browseable/WearDrawers/src/com.example.android.wearable.wear.weardrawers/MainActivity.java
@@ -27,11 +27,10 @@ import android.support.wearable.view.drawer.WearableNavigationDrawer;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.Toast;
@@ -86,17 +85,22 @@ public class MainActivity extends WearableActivity implements
(WearableNavigationDrawer) findViewById(R.id.top_navigation_drawer);
mWearableNavigationDrawer.setAdapter(new NavigationAdapter(this));
- // Peeks Navigation drawer on the top.
- mWearableDrawerLayout.peekDrawer(Gravity.TOP);
-
// Bottom Action Drawer
mWearableActionDrawer =
(WearableActionDrawer) findViewById(R.id.bottom_action_drawer);
mWearableActionDrawer.setOnMenuItemClickListener(this);
- // Peeks action drawer on the bottom.
- mWearableDrawerLayout.peekDrawer(Gravity.BOTTOM);
+ // Temporarily peeks the navigation and action drawers to ensure the user is aware of them.
+ ViewTreeObserver observer = mWearableDrawerLayout.getViewTreeObserver();
+ observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ mWearableDrawerLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ mWearableDrawerLayout.peekDrawer(Gravity.TOP);
+ mWearableDrawerLayout.peekDrawer(Gravity.BOTTOM);
+ }
+ });
/* Action Drawer Tip: If you only have a single action for your Action Drawer, you can use a
* (custom) View to peek on top of the content by calling
diff --git a/samples/browseable/WearHighBandwidthNetworking/AndroidManifest.xml b/samples/browseable/WearHighBandwidthNetworking/AndroidManifest.xml
new file mode 100644
index 000000000..bc25c0ef4
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/AndroidManifest.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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 package="com.example.android.wearable.wear.wearhighbandwidthnetworking"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-feature android:name="android.hardware.type.watch" />
+
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+
+ <meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="true" />
+
+ <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> \ No newline at end of file
diff --git a/samples/browseable/WearHighBandwidthNetworking/_index.jd b/samples/browseable/WearHighBandwidthNetworking/_index.jd
new file mode 100644
index 000000000..2754d2f40
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/_index.jd
@@ -0,0 +1,13 @@
+
+page.tags="WearHighBandwidthNetworking"
+sample.group=Wearable
+@jd:body
+
+<p>
+
+Sample demonstrates how to determine if a high-bandwidth network is available for use cases that
+require a minimum network bandwidth, such as streaming media or downloading large files. In
+addition, the sample demonstrates best practices for asking a user to add a new Wi-Fi network for
+high-bandwidth network operations if the bandwidth of currently available networks is inadequate.
+
+ </p>
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/drawable/bg_action_button.xml b/samples/browseable/WearHighBandwidthNetworking/res/drawable/bg_action_button.xml
new file mode 100644
index 000000000..a337ab1dd
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/drawable/bg_action_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval" />
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_cloud_disconnected.xml b/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_cloud_disconnected.xml
new file mode 100644
index 000000000..d93cc1137
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_cloud_disconnected.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M19.35 10.04C18.67 6.59 15.64 4 12 4c-1.48 0-2.85.43-4.01 1.17l1.46 1.46C10.21 6.23 11.08 6 12 6c3.04 0 5.5 2.46 5.5 5.5v.5H19c1.66 0 3 1.34 3 3 0 1.13-.64 2.11-1.56 2.62l1.45 1.45C23.16 18.16 24 16.68 24 15c0-2.64-2.05-4.78-4.65-4.96zM3 5.27l2.75 2.74C2.56 8.15 0 10.77 0 14c0 3.31 2.69 6 6 6h11.73l2 2L21 20.73 4.27 4 3 5.27zM7.73 10l8 8H6c-2.21 0-4-1.79-4-4s1.79-4 4-4h1.73z" />
+
+</vector>
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_cloud_happy.xml b/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_cloud_happy.xml
new file mode 100644
index 000000000..91cd65609
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_cloud_happy.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M19.35,10.04 C18.67,6.59,15.64,4,12,4 C9.11,4,6.6,5.64,5.35,8.04
+C2.34,8.36,0,10.91,0,14 C0,17.31,2.69,20,6,20 L19,20 C21.76,20,24,17.76,24,15
+C24,12.36,21.95,10.22,19.35,10.04 Z M19,18 L6,18 C3.79,18,2,16.21,2,14
+S3.79,10,6,10 L6.71,10 C7.37,7.69,9.48,6,12,6 C15.04,6,17.5,8.46,17.5,11.5
+L17.5,12 L19,12 C20.66,12,22,13.34,22,15 S20.66,18,19,18 Z" />
+ <path
+ android:strokeColor="#000000"
+ android:strokeWidth="2"
+ android:pathData="M6.58994,13.1803 C6.58994,13.1803,8.59173,15.8724,12.011,15.8726
+C15.2788,15.8728,17.3696,13.2502,17.3696,13.2502" />
+</vector>
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_cloud_sad.xml b/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_cloud_sad.xml
new file mode 100644
index 000000000..5b02f00a6
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_cloud_sad.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M19.35,10.04 C18.67,6.59,15.64,4,12,4 C9.11,4,6.6,5.64,5.35,8.04
+C2.34,8.36,0,10.91,0,14 C0,17.31,2.69,20,6,20 L19,20 C21.76,20,24,17.76,24,15
+C24,12.36,21.95,10.22,19.35,10.04 Z M19,18 L6,18 C3.79,18,2,16.21,2,14
+S3.79,10,6,10 L6.71,10 C7.37,7.69,9.48,6,12,6 C15.04,6,17.5,8.46,17.5,11.5
+L17.5,12 L19,12 C20.66,12,22,13.34,22,15 S20.66,18,19,18 Z" />
+ <path
+ android:strokeColor="#000000"
+ android:strokeWidth="2"
+ android:pathData="M6.58994,15.9661 C6.58994,15.9661,8.56048,12.5553,11.9798,12.5551
+C15.2476,12.5549,17.3696,15.8962,17.3696,15.8962" />
+</vector>
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_fast_network.xml b/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_fast_network.xml
new file mode 100644
index 000000000..378c5ea44
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_fast_network.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path android:fillColor="#fff"
+ android:pathData="M15.9 5c-.17 0-.32.09-.41.23l-.07.15-5.18 11.65c-.16.29-.26.61-.26.96 0 1.11.9 2.01 2.01 2.01.96 0 1.77-.68 1.96-1.59l.01-.03L16.4 5.5c0-.28-.22-.5-.5-.5zM1 9l2 2c2.88-2.88 6.79-4.08 10.53-3.62l1.19-2.68C9.89 3.84 4.74 5.27 1 9zm20 2l2-2c-1.64-1.64-3.55-2.82-5.59-3.57l-.53 2.82c1.5.62 2.9 1.53 4.12 2.75zm-4 4l2-2c-.8-.8-1.7-1.42-2.66-1.89l-.55 2.92c.42.27.83.59 1.21.97zM5 13l2 2c1.13-1.13 2.56-1.79 4.03-2l1.28-2.88c-2.63-.08-5.3.87-7.31 2.88z"/>
+
+</vector>
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_no_network.xml b/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_no_network.xml
new file mode 100644
index 000000000..e8d8ecce7
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_no_network.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path android:fillColor="#fff"
+ android:pathData="M23.64 7c-.45-.34-4.93-4-11.64-4-1.5 0-2.89.19-4.15.48L18.18 13.8 23.64 7zm-6.6 8.22L3.27 1.44 2 2.72l2.05 2.06C1.91 5.76.59 6.82.36 7l11.63 14.49.01.01.01-.01 3.9-4.86 3.32 3.32 1.27-1.27-3.46-3.46z"/>
+
+</vector>
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_wifi_network.xml b/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_wifi_network.xml
new file mode 100644
index 000000000..c25b99f69
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/drawable/ic_wifi_network.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path android:fillColor="#fff"
+ android:pathData="M3.53 10.95l8.46 10.54.01.01.01-.01 8.46-10.54C20.04 10.62 16.81 8 12 8c-4.81 0-8.04 2.62-8.47 2.95z"/>
+
+</vector>
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/layout/activity_main.xml b/samples/browseable/WearHighBandwidthNetworking/res/layout/activity_main.xml
new file mode 100644
index 000000000..9b716d964
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/layout/activity_main.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical"
+ tools:context="com.example.android.wearable.wear.wearhighbandwidthnetworking.MainActivity">
+
+ <RelativeLayout
+ android:id="@+id/connectivity_indicator"
+ android:layout_height="56dp"
+ android:layout_width="match_parent"
+ android:paddingTop="12dp"
+ style="@style/connectivity_indicator">
+
+ <ImageView
+ android:id="@+id/connectivity_icon"
+ android:layout_centerHorizontal="true"
+ android:src="@drawable/ic_cloud_disconnected"
+ style="@style/connectivity_indicator_icon" />
+
+ <TextView
+ android:id="@+id/connectivity_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/connectivity_icon"
+ android:layout_centerHorizontal="true"
+ android:text="@string/network_disconnected"
+ style="@style/connectivity_indicator_text" />
+
+ </RelativeLayout>
+
+ <android.support.wearable.view.BoxInsetLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:layout_box="left|right">
+
+ <TextView
+ android:id="@+id/info_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="10dp"
+ android:paddingBottom="10dp"
+ android:text="@string/info_request_network"
+ android:textAlignment="center" />
+
+ <RelativeLayout
+ android:id="@+id/button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/info_text"
+ android:focusable="true"
+ android:onClick="onButtonClick">
+
+ <ImageView
+ android:id="@+id/button_icon"
+ android:src="@drawable/ic_fast_network"
+ style="@style/action_button" />
+
+ <TextView
+ android:id="@+id/button_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_toRightOf="@id/button_icon"
+ android:layout_centerVertical="true"
+ android:text="@string/button_request_network" />
+
+ </RelativeLayout>
+
+ <ProgressBar
+ android:id="@+id/progress_bar"
+ android:layout_width="100dp"
+ android:layout_height="100dp"
+ android:layout_centerInParent="true"
+ android:indeterminate="true"
+ android:visibility="gone" />
+
+ </RelativeLayout>
+ </android.support.wearable.view.BoxInsetLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/mipmap-hdpi/ic_launcher.png b/samples/browseable/WearHighBandwidthNetworking/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..cde69bccc
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/mipmap-mdpi/ic_launcher.png b/samples/browseable/WearHighBandwidthNetworking/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..c133a0cbd
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/mipmap-xhdpi/ic_launcher.png b/samples/browseable/WearHighBandwidthNetworking/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..bfa42f0e7
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/mipmap-xxhdpi/ic_launcher.png b/samples/browseable/WearHighBandwidthNetworking/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..324e72cdd
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/values/colors.xml b/samples/browseable/WearHighBandwidthNetworking/res/values/colors.xml
new file mode 100644
index 000000000..30bf46cb3
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/values/colors.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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>
+ <!-- Colors for primary UI elements -->
+ <item name="primary" type="color">@color/indigo</item>
+ <item name="primary_dark" type="color">@color/indigo_40b</item>
+ <item name="primary_accent" type="color">@color/indigo_100b</item>
+ <item name="window_background" type="color">@color/indigo_15b</item>
+
+ <item name="text_primary" type="color">#CCBBBBBB</item>
+ <item name="text_dark" type="color">#CC000000</item>
+
+ <item name="white_80a" type="color">#CCFFFFFF</item>
+ <item name="white_70a" type="color">#B3FFFFFF</item>
+ <item name="white_60a" type="color">#99FFFFFF</item>
+ <item name="white_50a" type="color">#80FFFFFF</item>
+
+ <!-- Material Design Indigo 500 palette for wearables -->
+ <item name="indigo" type="color">#FF3F51B5</item>
+ <item name="indigo_100b" type="color">#FF8093FF</item>
+ <item name="indigo_65b" type="color">#FF3A4AA6</item>
+ <item name="indigo_40b" type="color">#FF242E66</item>
+ <item name="indigo_30b" type="color">#FF000B4D</item>
+ <item name="indigo_15b" type="color">#FF000626</item>
+
+ <!-- Alert overlay colors -->
+ <item name="connectivity_indicator_text" type="color">#9d9d9d</item>
+ <item name="connectivity_indicator_bg" type="color">#434343</item>
+</resources>
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/values/dimens.xml b/samples/browseable/WearHighBandwidthNetworking/res/values/dimens.xml
new file mode 100644
index 000000000..39aecced5
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/values/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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>
+ <!-- Generic text dimensions for styles -->
+ <dimen name="text_large">22sp</dimen>
+ <dimen name="text_medium">16sp</dimen>
+ <dimen name="text_small">12sp</dimen>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/values/strings.xml b/samples/browseable/WearHighBandwidthNetworking/res/values/strings.xml
new file mode 100644
index 000000000..c80585604
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/values/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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">Wear High Bandwidth Networking</string>
+
+ <string name="network_fast">Network Fast</string>
+ <string name="network_slow">Network Slow</string>
+ <string name="network_disconnected">Disconnected</string>
+ <string name="network_connecting">Connecting</string>
+
+ <string name="info_request_network">To use this sample, ensure that you have removed saved Wi-Fi networks and the device is unplugged</string>
+ <string name="info_release_network">A high-bandwidth network is now available</string>
+ <string name="info_add_wifi">No high-bandwidth network is available. You must add a Wi-Fi network to continue</string>
+
+ <string name="button_request_network">Request High-bandwidth Network</string>
+ <string name="button_release_network">Release High-bandwidth Network</string>
+ <string name="button_add_wifi">Add Wi-Fi Network</string>
+</resources>
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/values/styles.xml b/samples/browseable/WearHighBandwidthNetworking/res/values/styles.xml
new file mode 100644
index 000000000..97bbcce0b
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/values/styles.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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="text_header" parent="@android:style/Widget.TextView">
+ <item name="android:textColor">@color/text_primary</item>
+ <item name="android:textSize">@dimen/text_large</item>
+ </style>
+
+ <style name="text_normal" parent="@android:style/Widget.TextView">
+ <item name="android:textColor">@color/text_primary</item>
+ <item name="android:textSize">@dimen/text_medium</item>
+ </style>
+
+ <style name="text_small" parent="@android:style/Widget.TextView">
+ <item name="android:textColor">@color/text_primary</item>
+ <item name="android:textSize">@dimen/text_small</item>
+ </style>
+
+ <style name="action_button" parent="@android:style/Widget.ActionButton">
+ <item name="android:background">@drawable/bg_action_button</item>
+ <item name="android:backgroundTint">@color/primary</item>
+ <item name="android:tint">@color/white</item>
+ <item name="android:layout_width">40dp</item>
+ <item name="android:layout_height">40dp</item>
+ <item name="android:padding">8dp</item>
+ <item name="android:paddingStart">8dp</item>
+ <item name="android:paddingEnd">8dp</item>
+ <item name="android:scaleType">fitXY</item>
+ </style>
+
+ <style name="connectivity_indicator">
+ <item name="android:background">@color/connectivity_indicator_bg</item>
+ </style>
+
+ <style name="connectivity_indicator_text">
+ <item name="android:textColor">@color/connectivity_indicator_text</item>
+ <item name="android:textSize">14sp</item>
+ </style>
+
+ <style name="connectivity_indicator_icon">
+ <item name="android:tint">@color/connectivity_indicator_text</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">16dp</item>
+ </style>
+</resources>
diff --git a/samples/browseable/WearHighBandwidthNetworking/res/values/themes.xml b/samples/browseable/WearHighBandwidthNetworking/res/values/themes.xml
new file mode 100644
index 000000000..7f3054242
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/res/values/themes.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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="AppTheme" parent="@android:style/Theme.DeviceDefault">
+ <item name="android:colorPrimary">@color/primary</item>
+ <item name="android:colorPrimaryDark">@color/primary_dark</item>
+ <item name="android:colorAccent">@color/primary_accent</item>
+ <item name="android:windowBackground">@color/window_background</item>
+ </style>
+</resources>
diff --git a/samples/browseable/WearHighBandwidthNetworking/src/com.example.android.wearable.wear.wearhighbandwidthnetworking/MainActivity.java b/samples/browseable/WearHighBandwidthNetworking/src/com.example.android.wearable.wear.wearhighbandwidthnetworking/MainActivity.java
new file mode 100644
index 000000000..b2161ed6e
--- /dev/null
+++ b/samples/browseable/WearHighBandwidthNetworking/src/com.example.android.wearable.wear.wearhighbandwidthnetworking/MainActivity.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2016 Google Inc. All Rights Reserved.
+ *
+ * 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.wearable.wear.wearhighbandwidthnetworking;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This sample demonstrates how to determine if a high-bandwidth network is available for use cases
+ * that require a minimum network bandwidth, such as streaming media or downloading large files.
+ * In addition, the sample demonstrates best practices for asking a user to add a new Wi-Fi network
+ * for high-bandwidth network operations, if currently available networks are inadequate.
+ */
+public class MainActivity extends Activity {
+ private static final String LOG_TAG = MainActivity.class.getSimpleName();
+
+ // Intent action for sending the user directly to the add Wi-Fi network activity.
+ private static final String ACTION_ADD_NETWORK_SETTINGS =
+ "com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS";
+
+ // Message to notify the network request timout handler that too much time has passed.
+ private static final int MESSAGE_CONNECTIVITY_TIMEOUT = 1;
+
+ // How long the app should wait trying to connect to a sufficient high-bandwidth network before
+ // asking the user to add a new Wi-Fi network.
+ private static final long NETWORK_CONNECTIVITY_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
+
+ // The minimum network bandwidth required by the app for high-bandwidth operations.
+ private static final int MIN_NETWORK_BANDWIDTH_KBPS = 10000;
+
+ private ConnectivityManager mConnectivityManager;
+ private ConnectivityManager.NetworkCallback mNetworkCallback;
+
+ // Handler for dealing with network connection timeouts.
+ private Handler mHandler;
+
+ private ImageView mConnectivityIcon;
+ private TextView mConnectivityText;
+
+ private View mButton;
+ private ImageView mButtonIcon;
+ private TextView mButtonText;
+ private TextView mInfoText;
+ private View mProgressBar;
+
+ // Tags added to the button in the UI to detect what operation the user has requested.
+ // These are required since the app reuses the button for different states of the app/UI.
+ // See onButtonClick() for how these tags are used.
+ static final String TAG_REQUEST_NETWORK = "REQUEST_NETWORK";
+ static final String TAG_RELEASE_NETWORK = "RELEASE_NETWORK";
+ static final String TAG_ADD_WIFI = "ADD_WIFI";
+
+ // These constants are used by setUiState() to determine what information to display in the UI,
+ // as this app reuses UI components for the various states of the app, which is dependent on
+ // the state of the network.
+ static final int UI_STATE_REQUEST_NETWORK = 1;
+ static final int UI_STATE_REQUESTING_NETWORK = 2;
+ static final int UI_STATE_NETWORK_CONNECTED = 3;
+ static final int UI_STATE_CONNECTION_TIMEOUT = 4;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ mConnectivityIcon = (ImageView) findViewById(R.id.connectivity_icon);
+ mConnectivityText = (TextView) findViewById(R.id.connectivity_text);
+
+ mProgressBar = findViewById(R.id.progress_bar);
+
+ mButton = findViewById(R.id.button);
+ mButton.setTag(TAG_REQUEST_NETWORK);
+ mButtonIcon = (ImageView) findViewById(R.id.button_icon);
+ mButtonText = (TextView) findViewById(R.id.button_label);
+
+ mInfoText = (TextView) findViewById(R.id.info_text);
+
+ mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_CONNECTIVITY_TIMEOUT:
+ Log.d(LOG_TAG, "Network connection timeout");
+ setUiState(UI_STATE_CONNECTION_TIMEOUT);
+ unregisterNetworkCallback();
+ break;
+ }
+ }
+ };
+ }
+
+ @Override
+ public void onStop() {
+ releaseHighBandwidthNetwork();
+ super.onStop();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ if (isNetworkHighBandwidth()) {
+ setUiState(UI_STATE_NETWORK_CONNECTED);
+ } else {
+ setUiState(UI_STATE_REQUEST_NETWORK);
+ }
+ }
+
+ private void unregisterNetworkCallback() {
+ if (mNetworkCallback != null) {
+ Log.d(LOG_TAG, "Unregistering network callback");
+ mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
+ mNetworkCallback = null;
+ }
+ }
+
+ // Determine if there is a high-bandwidth network exists. Checks both the active
+ // and bound networks. Returns false if no network is available (low or high-bandwidth).
+ private boolean isNetworkHighBandwidth() {
+ Network network = mConnectivityManager.getBoundNetworkForProcess();
+ network = network == null ? mConnectivityManager.getActiveNetwork() : network;
+ if (network == null) {
+ return false;
+ }
+
+ // requires android.permission.ACCESS_NETWORK_STATE
+ int bandwidth = mConnectivityManager
+ .getNetworkCapabilities(network).getLinkDownstreamBandwidthKbps();
+
+ if (bandwidth >= MIN_NETWORK_BANDWIDTH_KBPS) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private void requestHighBandwidthNetwork() {
+ // Before requesting a high-bandwidth network, ensure prior requests are invalidated.
+ unregisterNetworkCallback();
+
+ Log.d(LOG_TAG, "Requesting high-bandwidth network");
+
+ // Requesting an unmetered network may prevent you from connecting to the cellular
+ // network on the user's watch or phone; however, unless you explicitly ask for permission
+ // to a access the user's cellular network, you should request an unmetered network.
+ NetworkRequest request = new NetworkRequest.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .build();
+
+ mNetworkCallback = new ConnectivityManager.NetworkCallback() {
+ @Override
+ public void onAvailable(final Network network) {
+ mHandler.removeMessages(MESSAGE_CONNECTIVITY_TIMEOUT);
+
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // requires android.permission.INTERNET
+ if (!mConnectivityManager.bindProcessToNetwork(network)) {
+ Log.e(LOG_TAG, "ConnectivityManager.bindProcessToNetwork()"
+ + " requires android.permission.INTERNET");
+ setUiState(UI_STATE_REQUEST_NETWORK);
+ } else {
+ Log.d(LOG_TAG, "Network available");
+ setUiState(UI_STATE_NETWORK_CONNECTED);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onCapabilitiesChanged(Network network,
+ NetworkCapabilities networkCapabilities) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Log.d(LOG_TAG, "Network capabilities changed");
+ }
+ });
+ }
+
+ @Override
+ public void onLost(Network network) {
+ Log.d(LOG_TAG, "Network lost");
+
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ setUiState(UI_STATE_REQUEST_NETWORK);
+ }
+ });
+ }
+ };
+
+ // requires android.permission.CHANGE_NETWORK_STATE
+ mConnectivityManager.requestNetwork(request, mNetworkCallback);
+
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MESSAGE_CONNECTIVITY_TIMEOUT),
+ NETWORK_CONNECTIVITY_TIMEOUT_MS);
+ }
+
+ private void releaseHighBandwidthNetwork() {
+ mConnectivityManager.bindProcessToNetwork(null);
+ unregisterNetworkCallback();
+ }
+
+ private void addWifiNetwork() {
+ // requires android.permission.CHANGE_WIFI_STATE
+ startActivity(new Intent(ACTION_ADD_NETWORK_SETTINGS));
+ }
+
+ /**
+ * Click handler for the button in the UI. The view tag is used to determine the specific
+ * function of the button.
+ *
+ * @param view The view that was clicked
+ */
+ public void onButtonClick(View view) {
+ switch (view.getTag().toString()) {
+ case TAG_REQUEST_NETWORK:
+ requestHighBandwidthNetwork();
+ setUiState(UI_STATE_REQUESTING_NETWORK);
+ break;
+
+ case TAG_RELEASE_NETWORK:
+ releaseHighBandwidthNetwork();
+ setUiState(UI_STATE_REQUEST_NETWORK);
+ break;
+
+ case TAG_ADD_WIFI:
+ addWifiNetwork();
+ break;
+ }
+ }
+
+ // Sets the text and icons the connectivity indicator, button, and info text in the app UI,
+ // which are all reused for the various states of the app and network connectivity. Also,
+ // will show/hide a progress bar, which is dependent on the state of the network connectivity
+ // request.
+ private void setUiState(int uiState) {
+ switch (uiState) {
+ case UI_STATE_REQUEST_NETWORK:
+ if (isNetworkHighBandwidth()) {
+ mConnectivityIcon.setImageResource(R.drawable.ic_cloud_happy);
+ mConnectivityText.setText(R.string.network_fast);
+ } else {
+ mConnectivityIcon.setImageResource(R.drawable.ic_cloud_sad);
+ mConnectivityText.setText(R.string.network_slow);
+ }
+
+ mButton.setTag(TAG_REQUEST_NETWORK);
+ mButtonIcon.setImageResource(R.drawable.ic_fast_network);
+ mButtonText.setText(R.string.button_request_network);
+ mInfoText.setText(R.string.info_request_network);
+
+ break;
+
+ case UI_STATE_REQUESTING_NETWORK:
+ mConnectivityIcon.setImageResource(R.drawable.ic_cloud_disconnected);
+ mConnectivityText.setText(R.string.network_connecting);
+
+ mProgressBar.setVisibility(View.VISIBLE);
+ mInfoText.setVisibility(View.GONE);
+ mButton.setVisibility(View.GONE);
+
+ break;
+
+ case UI_STATE_NETWORK_CONNECTED:
+ if (isNetworkHighBandwidth()) {
+ mConnectivityIcon.setImageResource(R.drawable.ic_cloud_happy);
+ mConnectivityText.setText(R.string.network_fast);
+ } else {
+ mConnectivityIcon.setImageResource(R.drawable.ic_cloud_sad);
+ mConnectivityText.setText(R.string.network_slow);
+ }
+
+ mProgressBar.setVisibility(View.GONE);
+ mInfoText.setVisibility(View.VISIBLE);
+ mButton.setVisibility(View.VISIBLE);
+
+ mButton.setTag(TAG_RELEASE_NETWORK);
+ mButtonIcon.setImageResource(R.drawable.ic_no_network);
+ mButtonText.setText(R.string.button_release_network);
+ mInfoText.setText(R.string.info_release_network);
+
+ break;
+
+ case UI_STATE_CONNECTION_TIMEOUT:
+ mConnectivityIcon.setImageResource(R.drawable.ic_cloud_disconnected);
+ mConnectivityText.setText(R.string.network_disconnected);
+
+ mProgressBar.setVisibility(View.GONE);
+ mInfoText.setVisibility(View.VISIBLE);
+ mButton.setVisibility(View.VISIBLE);
+
+ mButton.setTag(TAG_ADD_WIFI);
+ mButtonIcon.setImageResource(R.drawable.ic_wifi_network);
+ mButtonText.setText(R.string.button_add_wifi);
+ mInfoText.setText(R.string.info_add_wifi);
+
+ break;
+ }
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/WearNotifications/Application/res/values/base-strings.xml b/samples/browseable/WearNotifications/Application/res/values/base-strings.xml
index 554428945..e6aee0d87 100644
--- a/samples/browseable/WearNotifications/Application/res/values/base-strings.xml
+++ b/samples/browseable/WearNotifications/Application/res/values/base-strings.xml
@@ -16,7 +16,7 @@
-->
<resources>
- <string name="app_name">Wear Notifications</string>
+ <string name="app_name">WearNotifications</string>
<string name="intro_message">
<![CDATA[
diff --git a/samples/browseable/WearNotifications/Wearable/AndroidManifest.xml b/samples/browseable/WearNotifications/Wearable/AndroidManifest.xml
index 95176561b..2fdee0d3b 100644
--- a/samples/browseable/WearNotifications/Wearable/AndroidManifest.xml
+++ b/samples/browseable/WearNotifications/Wearable/AndroidManifest.xml
@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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.wearable.wear.wearnotifications"
android:versionCode="1"
@@ -27,7 +27,10 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
- android:theme="@android:style/Theme.DeviceDefault">
+ android:theme="@style/AppThemeOverride">
+
+ <!-- Let's Play Store know this app is standalone. -->
+ <meta-data android:name="com.google.android.wearable.standalone" android:value="true"/>
<!--
Important Note: Usually, you will want to disable bridging if you have a local/native
diff --git a/samples/browseable/WearNotifications/Wearable/res/drawable-hdpi/ic_n_white_48dp.png b/samples/browseable/WearNotifications/Wearable/res/drawable-hdpi/ic_n_white_48dp.png
new file mode 100644
index 000000000..33eceae3f
--- /dev/null
+++ b/samples/browseable/WearNotifications/Wearable/res/drawable-hdpi/ic_n_white_48dp.png
Binary files differ
diff --git a/samples/browseable/WearNotifications/Wearable/res/layout/activity_big_picture_main.xml b/samples/browseable/WearNotifications/Wearable/res/layout/activity_big_picture_main.xml
index c52cd05dc..f9de46cc6 100644
--- a/samples/browseable/WearNotifications/Wearable/res/layout/activity_big_picture_main.xml
+++ b/samples/browseable/WearNotifications/Wearable/res/layout/activity_big_picture_main.xml
@@ -1,28 +1,28 @@
<?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.
--->
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_header_end_padding"
- android:paddingLeft="@dimen/list_start_padding"
- android:paddingRight="@dimen/list_end_padding"
- android:paddingTop="@dimen/activity_header_start_padding"
+ android:paddingBottom="@dimen/activity_notification_details_bottom_padding"
+ android:paddingLeft="@dimen/activity_notification_details_right_padding"
+ android:paddingRight="@dimen/activity_notification_details_left_padding"
+ android:paddingTop="@dimen/activity_notification_details_top_padding"
tools:context=".handlers.BigPictureSocialMainActivity">
<TextView
diff --git a/samples/browseable/WearNotifications/Wearable/res/layout/activity_big_text_main.xml b/samples/browseable/WearNotifications/Wearable/res/layout/activity_big_text_main.xml
index 946942682..29d9ba6e4 100644
--- a/samples/browseable/WearNotifications/Wearable/res/layout/activity_big_text_main.xml
+++ b/samples/browseable/WearNotifications/Wearable/res/layout/activity_big_text_main.xml
@@ -1,28 +1,28 @@
<?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.
--->
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_header_end_padding"
- android:paddingLeft="@dimen/list_start_padding"
- android:paddingRight="@dimen/list_end_padding"
- android:paddingTop="@dimen/activity_header_start_padding"
+ android:paddingBottom="@dimen/activity_notification_details_bottom_padding"
+ android:paddingLeft="@dimen/activity_notification_details_right_padding"
+ android:paddingRight="@dimen/activity_notification_details_left_padding"
+ android:paddingTop="@dimen/activity_notification_details_top_padding"
tools:context=".handlers.BigTextMainActivity">
<TextView
diff --git a/samples/browseable/WearNotifications/Wearable/res/layout/activity_inbox_main.xml b/samples/browseable/WearNotifications/Wearable/res/layout/activity_inbox_main.xml
index 3123ecba8..0925af569 100644
--- a/samples/browseable/WearNotifications/Wearable/res/layout/activity_inbox_main.xml
+++ b/samples/browseable/WearNotifications/Wearable/res/layout/activity_inbox_main.xml
@@ -1,28 +1,28 @@
<?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.
--->
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_header_end_padding"
- android:paddingLeft="@dimen/list_start_padding"
- android:paddingRight="@dimen/list_end_padding"
- android:paddingTop="@dimen/activity_header_start_padding"
+ android:paddingBottom="@dimen/activity_notification_details_bottom_padding"
+ android:paddingLeft="@dimen/activity_notification_details_right_padding"
+ android:paddingRight="@dimen/activity_notification_details_left_padding"
+ android:paddingTop="@dimen/activity_notification_details_top_padding"
tools:context=".handlers.InboxMainActivity">
<TextView
diff --git a/samples/browseable/WearNotifications/Wearable/res/layout/activity_main.xml b/samples/browseable/WearNotifications/Wearable/res/layout/activity_main.xml
index 467b461c9..5dc46fdd4 100644
--- a/samples/browseable/WearNotifications/Wearable/res/layout/activity_main.xml
+++ b/samples/browseable/WearNotifications/Wearable/res/layout/activity_main.xml
@@ -1,53 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2016 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
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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/mainRelativeLayout"
+ android:id="@+id/mainFrameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_header_end_padding"
- android:paddingLeft="@dimen/list_start_padding"
- android:paddingRight="@dimen/list_end_padding"
- android:paddingTop="@dimen/activity_header_start_padding"
tools:context="com.example.android.wearable.wear.wearnotifications.StandaloneMainActivity">
- <TextView
+ <android.support.wearable.view.WearableRecyclerView
+ android:id="@+id/recycler_view"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Pick Notification Style:"
- android:id="@+id/spinnerHeadertextView"/>
-
- <!--
- android:paddingTop="@dimen/activity_vertical_margin"
- -->
+ android:layout_height="match_parent"
+ android:scrollbars="vertical" />
- <Spinner
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/spinner"
- android:layout_below="@+id/spinnerHeadertextView"/>
-
- <Button
+ <TextView
+ android:id="@+id/header_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="Launch!"
- android:onClick="onClick"
- android:layout_below="@+id/spinner"
- android:id="@+id/submit"/>
-
-</RelativeLayout> \ No newline at end of file
+ android:textAlignment="center"
+ android:paddingTop="@dimen/activity_main_text_header_spacing"
+ android:paddingBottom="@dimen/activity_main_text_header_spacing"
+ android:background="@color/grey"
+ android:text="@string/floating_text"/>
+</FrameLayout> \ No newline at end of file
diff --git a/samples/browseable/WearNotifications/Wearable/res/layout/activity_messaging_main.xml b/samples/browseable/WearNotifications/Wearable/res/layout/activity_messaging_main.xml
index 0a710d0dd..f33696576 100644
--- a/samples/browseable/WearNotifications/Wearable/res/layout/activity_messaging_main.xml
+++ b/samples/browseable/WearNotifications/Wearable/res/layout/activity_messaging_main.xml
@@ -1,28 +1,28 @@
<?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.
--->
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_header_end_padding"
- android:paddingLeft="@dimen/list_start_padding"
- android:paddingRight="@dimen/list_end_padding"
- android:paddingTop="@dimen/activity_header_start_padding"
+ android:paddingBottom="@dimen/activity_notification_details_bottom_padding"
+ android:paddingLeft="@dimen/activity_notification_details_right_padding"
+ android:paddingRight="@dimen/activity_notification_details_left_padding"
+ android:paddingTop="@dimen/activity_notification_details_top_padding"
tools:context=".handlers.MessagingMainActivity">
<TextView
diff --git a/samples/browseable/WearNotifications/Wearable/res/layout/recycler_row_item.xml b/samples/browseable/WearNotifications/Wearable/res/layout/recycler_row_item.xml
new file mode 100644
index 000000000..60c577ed0
--- /dev/null
+++ b/samples/browseable/WearNotifications/Wearable/res/layout/recycler_row_item.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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="wrap_content"
+ android:layout_gravity="center"
+ android:paddingTop="@dimen/recycler_row_padding"
+ android:paddingBottom="@dimen/recycler_row_padding"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_n_white_48dp"/>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:textSize="@dimen/recycler_row_text_size"
+ android:id="@+id/textView"/>
+</LinearLayout> \ No newline at end of file
diff --git a/samples/browseable/WearNotifications/Wearable/res/values-round/dimens.xml b/samples/browseable/WearNotifications/Wearable/res/values-round/dimens.xml
index 0bfb8a0d8..d7a0e57e2 100644
--- a/samples/browseable/WearNotifications/Wearable/res/values-round/dimens.xml
+++ b/samples/browseable/WearNotifications/Wearable/res/values-round/dimens.xml
@@ -1,22 +1,24 @@
<?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.
--->
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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="activity_header_start_padding">36dp</dimen>
- <dimen name="activity_header_end_padding">22dp</dimen>
- <dimen name="list_start_padding">36dp</dimen>
- <dimen name="list_end_padding">22dp</dimen>
+ <dimen name="recycler_row_text_size">20sp</dimen>
+
+ <dimen name="activity_notification_details_top_padding">36dp</dimen>
+ <dimen name="activity_notification_details_bottom_padding">22dp</dimen>
+ <dimen name="activity_notification_details_right_padding">36dp</dimen>
+ <dimen name="activity_notification_details_left_padding">22dp</dimen>
</resources>
diff --git a/samples/browseable/WearNotifications/Wearable/res/values-round/strings.xml b/samples/browseable/WearNotifications/Wearable/res/values-round/strings.xml
new file mode 100644
index 000000000..b8eb69e45
--- /dev/null
+++ b/samples/browseable/WearNotifications/Wearable/res/values-round/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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="floating_text">Pick\nNotification Style</string>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/WearNotifications/Wearable/res/values/colors.xml b/samples/browseable/WearNotifications/Wearable/res/values/colors.xml
index 752b74fc3..e1632c558 100644
--- a/samples/browseable/WearNotifications/Wearable/res/values/colors.xml
+++ b/samples/browseable/WearNotifications/Wearable/res/values/colors.xml
@@ -1,19 +1,19 @@
<?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.
--->
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
diff --git a/samples/browseable/WearNotifications/Wearable/res/values/dimens.xml b/samples/browseable/WearNotifications/Wearable/res/values/dimens.xml
index 05a0801db..e6d1996ea 100644
--- a/samples/browseable/WearNotifications/Wearable/res/values/dimens.xml
+++ b/samples/browseable/WearNotifications/Wearable/res/values/dimens.xml
@@ -1,22 +1,27 @@
<?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
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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="activity_main_text_header_spacing">5dp</dimen>
- http://www.apache.org/licenses/LICENSE-2.0
+ <dimen name="recycler_row_padding">5dp</dimen>
+ <dimen name="recycler_row_text_size">14sp</dimen>
- 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="activity_header_start_padding">16dp</dimen>
- <dimen name="activity_header_end_padding">16dp</dimen>
- <dimen name="list_start_padding">10dp</dimen>
- <dimen name="list_end_padding">10dp</dimen>
-</resources>
+ <dimen name="activity_notification_details_top_padding">5dp</dimen>
+ <dimen name="activity_notification_details_bottom_padding">5dp</dimen>
+ <dimen name="activity_notification_details_right_padding">5dp</dimen>
+ <dimen name="activity_notification_details_left_padding">5dp</dimen>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/WearNotifications/Wearable/res/values/strings.xml b/samples/browseable/WearNotifications/Wearable/res/values/strings.xml
index ee3edc2d0..8ea45fead 100644
--- a/samples/browseable/WearNotifications/Wearable/res/values/strings.xml
+++ b/samples/browseable/WearNotifications/Wearable/res/values/strings.xml
@@ -1,18 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2016 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 2016 Google Inc.
+ ~
+ ~ 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">Wear Notifications</string>
@@ -40,5 +41,6 @@
This Activity would handle the messaging app\'s functionality for a chat(s).
\n\nThe notification type for this example was the Messaging Style!
</string>
+ <string name="floating_text">Pick Notification Style</string>
</resources> \ No newline at end of file
diff --git a/samples/browseable/WearNotifications/Wearable/res/values/styles.xml b/samples/browseable/WearNotifications/Wearable/res/values/styles.xml
new file mode 100644
index 000000000..1d68f7309
--- /dev/null
+++ b/samples/browseable/WearNotifications/Wearable/res/values/styles.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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="AppThemeOverride" parent="Theme.AppCompat.NoActionBar" />
+</resources> \ No newline at end of file
diff --git a/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/Controller.java b/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/Controller.java
new file mode 100644
index 000000000..ee372bc6b
--- /dev/null
+++ b/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/Controller.java
@@ -0,0 +1,22 @@
+package com.example.android.wearable.wear.wearnotifications;
+
+import android.app.Notification;
+
+/**
+ * Controller used to instruct main activity to update {@link Notification} based on changes in
+ * the {@link CustomRecyclerAdapter} (item selected) which is tied to the
+ * {@link android.support.wearable.view.WearableRecyclerView}.
+ */
+
+public class Controller {
+
+ private StandaloneMainActivity mView;
+
+ Controller(StandaloneMainActivity standaloneMainActivity) {
+ mView = standaloneMainActivity;
+ }
+
+ public void itemSelected(String notificationStyleSelected) {
+ mView.itemSelected(notificationStyleSelected);
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/CustomRecyclerAdapter.java b/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/CustomRecyclerAdapter.java
new file mode 100644
index 000000000..6bdcac371
--- /dev/null
+++ b/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/CustomRecyclerAdapter.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 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.wearable.wear.wearnotifications;
+
+import android.widget.ImageView;
+
+import android.support.v4.app.NotificationCompat;
+import android.support.wearable.view.WearableRecyclerView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * Provides a binding from {@link NotificationCompat.Style} data set to views displayed within the
+ * {@link WearableRecyclerView}.
+ */
+public class CustomRecyclerAdapter extends
+ WearableRecyclerView.Adapter<CustomRecyclerAdapter.ViewHolder> {
+
+ private static final String TAG = "CustomRecyclerAdapter";
+
+ private String[] mDataSet;
+
+ // Custom Controller used to instruct main activity to update {@link Notification} and/or
+ // UI for item selected.
+ private Controller mController;
+
+ /**
+ * Provides reference to the views for each data item. We don't maintain a reference to the
+ * {@link ImageView} (representing the icon), because it does not change for each item. We
+ * wanted to keep the sample simple, but you could add extra code to customize each icon.
+ */
+ public static class ViewHolder extends WearableRecyclerView.ViewHolder {
+
+ private final TextView mTextView;
+
+ public ViewHolder(View view) {
+ super(view);
+ mTextView = (TextView) view.findViewById(R.id.textView);
+ }
+
+ @Override
+ public String toString() { return (String) mTextView.getText(); }
+ }
+
+ public CustomRecyclerAdapter(String[] dataSet, Controller controller) {
+ mDataSet = dataSet;
+ mController = controller;
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
+ View view = LayoutInflater.from(viewGroup.getContext())
+ .inflate(R.layout.recycler_row_item, viewGroup, false);
+
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder viewHolder, final int position) {
+ Log.d(TAG, "Element " + position + " set.");
+
+ viewHolder.mTextView.setOnClickListener(new View.OnClickListener() {
+
+ @Override
+ public void onClick(View view) {
+ mController.itemSelected(mDataSet[position]);
+ }
+ });
+
+ // Replaces content of view with correct element from data set
+ viewHolder.mTextView.setText(mDataSet[position]);
+ }
+
+ // Return the size of your dataset (invoked by the layout manager)
+ @Override
+ public int getItemCount() {
+ return mDataSet.length;
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/GlobalNotificationBuilder.java b/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/GlobalNotificationBuilder.java
index 4023fbb6e..427c7899a 100644
--- a/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/GlobalNotificationBuilder.java
+++ b/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/GlobalNotificationBuilder.java
@@ -1,17 +1,17 @@
/*
-Copyright 2016 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) 2016 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.wearable.wear.wearnotifications;
diff --git a/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/ScalingOffsettingHelper.java b/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/ScalingOffsettingHelper.java
new file mode 100644
index 000000000..84ec2fd33
--- /dev/null
+++ b/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/ScalingOffsettingHelper.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 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.wearable.wear.wearnotifications;
+
+import android.support.wearable.view.DefaultOffsettingHelper;
+import android.support.wearable.view.WearableRecyclerView;
+import android.view.View;
+
+/**
+ * Customizes all items (children) in a {@link WearableRecyclerView} to align to left side of
+ * surface/watch and shrinks each item (child) as you scroll away from it.
+ */
+public class ScalingOffsettingHelper extends DefaultOffsettingHelper {
+
+ // Max we scale the child View
+ private static final float MAX_CHILD_SCALE = 0.65f;
+
+ private float mProgressToCenter;
+
+ public ScalingOffsettingHelper() {}
+
+ // Shrinks icons/text and you scroll away
+ @Override
+ public void updateChild(View child, WearableRecyclerView parent) {
+ super.updateChild(child, parent);
+
+ // Figure out % progress from top to bottom
+ float centerOffset = ((float) child.getHeight() / 2.0f) / (float) parent.getHeight();
+ float yRelativeToCenterOffset = (child.getY() / parent.getHeight()) + centerOffset;
+
+ // Normalize for center
+ mProgressToCenter = Math.abs(0.5f - yRelativeToCenterOffset);
+
+ // Adjust to the maximum scale
+ mProgressToCenter = Math.min(mProgressToCenter, MAX_CHILD_SCALE);
+
+ child.setScaleX(1 - mProgressToCenter);
+ child.setScaleY(1 - mProgressToCenter);
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/StandaloneMainActivity.java b/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/StandaloneMainActivity.java
index a390aca43..95baa6dca 100644
--- a/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/StandaloneMainActivity.java
+++ b/samples/browseable/WearNotifications/Wearable/src/com.example.android.wearable.wear.wearnotifications/StandaloneMainActivity.java
@@ -1,17 +1,17 @@
/*
-Copyright 2016 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) 2016 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.wearable.wear.wearnotifications;
@@ -30,12 +30,10 @@ import android.support.v4.app.NotificationManagerCompat;
import android.support.v4.app.RemoteInput;
import android.support.v7.app.NotificationCompat;
import android.support.wearable.activity.WearableActivity;
+import android.support.wearable.view.WearableRecyclerView;
import android.util.Log;
import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.RelativeLayout;
-import android.widget.Spinner;
+import android.widget.FrameLayout;
import com.example.android.wearable.wear.wearnotifications.handlers.BigPictureSocialIntentService;
import com.example.android.wearable.wear.wearnotifications.handlers.BigPictureSocialMainActivity;
@@ -47,34 +45,39 @@ import com.example.android.wearable.wear.wearnotifications.handlers.MessagingMai
import com.example.android.wearable.wear.wearnotifications.mock.MockDatabase;
/**
- * Demonstrates best practice for Notifications created by local standalone Android Wear apps. All
- * Notification examples use Notification Styles.
+ * Demonstrates best practice for {@link NotificationCompat} Notifications created by local
+ * standalone Android Wear apps. All {@link NotificationCompat} examples use
+ * {@link NotificationCompat.Style}.
*/
-public class StandaloneMainActivity extends WearableActivity
- implements AdapterView.OnItemSelectedListener {
+public class StandaloneMainActivity extends WearableActivity {
private static final String TAG = "StandaloneMainActivity";
public static final int NOTIFICATION_ID = 888;
- // Used for Notification Style array and switch statement for Spinner selection
+ /*
+ * Used to represent each major {@link NotificationCompat.Style} in the
+ * {@link WearableRecyclerView}. These constants are also used in a switch statement when one
+ * of the items is selected to create the appropriate {@link Notification}.
+ */
private static final String BIG_TEXT_STYLE = "BIG_TEXT_STYLE";
private static final String BIG_PICTURE_STYLE = "BIG_PICTURE_STYLE";
private static final String INBOX_STYLE = "INBOX_STYLE";
private static final String MESSAGING_STYLE = "MESSAGING_STYLE";
- // Collection of notification styles to back ArrayAdapter for Spinner
+ /*
+ Collection of major {@link NotificationCompat.Style} to create {@link CustomRecyclerAdapter}
+ for {@link WearableRecyclerView}.
+ */
private static final String[] NOTIFICATION_STYLES =
{BIG_TEXT_STYLE, BIG_PICTURE_STYLE, INBOX_STYLE, MESSAGING_STYLE};
private NotificationManagerCompat mNotificationManagerCompat;
- private int mSelectedNotification = 0;
-
- // RelativeLayout is needed for SnackBars to alert users when Notifications are disabled for app
- private RelativeLayout mMainRelativeLayout;
- // TODO (jewalker): convert Spinner to WearableRecyclerView
- private Spinner mSpinner;
+ // Needed for {@link SnackBar} to alert users when {@link Notification} are disabled for app.
+ private FrameLayout mMainFrameLayout;
+ private WearableRecyclerView mWearableRecyclerView;
+ private CustomRecyclerAdapter mCustomRecyclerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -84,53 +87,49 @@ public class StandaloneMainActivity extends WearableActivity
setContentView(R.layout.activity_main);
setAmbientEnabled();
+ mNotificationManagerCompat = NotificationManagerCompat.from(getApplicationContext());
- mMainRelativeLayout = (RelativeLayout) findViewById(R.id.mainRelativeLayout);
- mSpinner = (Spinner) findViewById(R.id.spinner);
+ mMainFrameLayout = (FrameLayout) findViewById(R.id.mainFrameLayout);
+ mWearableRecyclerView = (WearableRecyclerView) findViewById(R.id.recycler_view);
- mNotificationManagerCompat = NotificationManagerCompat.from(getApplicationContext());
+ // Aligns the first and last items on the list vertically centered on the screen.
+ mWearableRecyclerView.setCenterEdgeItems(true);
- // Create an ArrayAdapter using the string array and a default spinner layout
- ArrayAdapter<CharSequence> adapter =
- new ArrayAdapter(
- this,
- android.R.layout.simple_spinner_item,
- NOTIFICATION_STYLES);
- // Specify the layout to use when the list of choices appears
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- // Apply the adapter to the spinner
- mSpinner.setAdapter(adapter);
- mSpinner.setOnItemSelectedListener(this);
+ // Customizes scrolling (zoom) and offsets of WearableRecyclerView's items
+ ScalingOffsettingHelper scalingOffsettingHelper = new ScalingOffsettingHelper();
+ mWearableRecyclerView.setOffsettingHelper(scalingOffsettingHelper);
- }
+ // Improves performance because we know changes in content do not change the layout size of
+ // the RecyclerView.
+ mWearableRecyclerView.setHasFixedSize(true);
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- Log.d(TAG, "onItemSelected(): position: " + position + " id: " + id);
+ // Specifies an adapter (see also next example).
+ mCustomRecyclerAdapter = new CustomRecyclerAdapter(
+ NOTIFICATION_STYLES,
+ // Controller passes selected data from the Adapter out to this Activity to trigger
+ // updates in the UI/Notifications.
+ new Controller(this));
- mSelectedNotification = position;
- }
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- // Required
+ mWearableRecyclerView.setAdapter(mCustomRecyclerAdapter);
}
- public void onClick(View view) {
+ // Called by WearableRecyclerView when an item is selected (check onCreate() for initialization)
+ public void itemSelected(String data) {
- Log.d(TAG, "onClick()");
+ Log.d(TAG, "itemSelected()");
boolean areNotificationsEnabled = mNotificationManagerCompat.areNotificationsEnabled();
- // TODO (jewalker): Verify this is required, can't find way to disable in Wear 2.0.
+ // If notifications are disabled, allow user to enable.
if (!areNotificationsEnabled) {
// Because the user took an action to create a notification, we create a prompt to let
// the user re-enable notifications for this application again.
Snackbar snackbar = Snackbar
.make(
- mMainRelativeLayout,
- "You need to enable notifications for this app",
+ mMainFrameLayout,
+ "", // Not enough space for both text and action text
Snackbar.LENGTH_LONG)
- .setAction("ENABLE", new View.OnClickListener() {
+ .setAction("Enable Notifications", new View.OnClickListener() {
@Override
public void onClick(View view) {
// Links to this app's notification settings
@@ -141,7 +140,7 @@ public class StandaloneMainActivity extends WearableActivity
return;
}
- String notificationStyle = NOTIFICATION_STYLES[mSelectedNotification];
+ String notificationStyle = data;
switch (notificationStyle) {
case BIG_TEXT_STYLE:
diff --git a/samples/browseable/WearNotifications/_index.jd b/samples/browseable/WearNotifications/_index.jd
index 1a89c1e82..3d774efc6 100644
--- a/samples/browseable/WearNotifications/_index.jd
+++ b/samples/browseable/WearNotifications/_index.jd
@@ -1,5 +1,5 @@
-page.tags="Wear Notifications"
+page.tags="WearNotifications"
sample.group=Wearable
@jd:body
diff --git a/samples/browseable/WearSpeakerSample/AndroidManifest.xml b/samples/browseable/WearSpeakerSample/AndroidManifest.xml
index 135d3e080..e8d9a2944 100644
--- a/samples/browseable/WearSpeakerSample/AndroidManifest.xml
+++ b/samples/browseable/WearSpeakerSample/AndroidManifest.xml
@@ -26,6 +26,11 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.DeviceDefault" >
+
+ <meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="true" />
+
<uses-library android:name="com.google.android.wearable" android:required="false" />
<activity
android:name=".MainActivity"
@@ -37,5 +42,4 @@
</intent-filter>
</activity>
</application>
-
-</manifest>
+</manifest> \ No newline at end of file
diff --git a/samples/browseable/WearVerifyRemoteApp/Application/AndroidManifest.xml b/samples/browseable/WearVerifyRemoteApp/Application/AndroidManifest.xml
new file mode 100644
index 000000000..af1ea86ba
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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.wearable.wear.wearverifyremoteapp"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@mipmap/ic_launcher"
+ android:theme="@style/AppThemeCustom">
+
+ <activity android:name=".MainMobileActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+
+ </application>
+</manifest> \ No newline at end of file
diff --git a/samples/browseable/WearVerifyRemoteApp/Application/res/drawable-hdpi/tile.9.png b/samples/browseable/WearVerifyRemoteApp/Application/res/drawable-hdpi/tile.9.png
new file mode 100644
index 000000000..135862883
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/WearVerifyRemoteApp/Application/res/layout/activity_main.xml b/samples/browseable/WearVerifyRemoteApp/Application/res/layout/activity_main.xml
new file mode 100644
index 000000000..d189f84ed
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/res/layout/activity_main.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ android:orientation="vertical"
+ tools:context="com.example.android.wearable.wear.wearverifyremoteapp.MainMobileActivity">
+
+ <TextView
+ android:id="@+id/information_text_view"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="5"/>
+
+ <Button
+ android:id="@+id/remote_open_button"
+ android:layout_width="match_parent"
+ android:text="Install App on Wear device(s)"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:visibility="invisible"/>
+</LinearLayout> \ No newline at end of file
diff --git a/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-hdpi/ic_launcher.png b/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..cde69bccc
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-mdpi/ic_launcher.png b/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..c133a0cbd
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-xhdpi/ic_launcher.png b/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..bfa42f0e7
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-xxhdpi/ic_launcher.png b/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..324e72cdd
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-xxxhdpi/ic_launcher.png b/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..aee44e138
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/WearVerifyRemoteApp/Application/res/values-sw600dp/template-dimens.xml b/samples/browseable/WearVerifyRemoteApp/Application/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 000000000..22074a2bd
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/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/samples/browseable/WearVerifyRemoteApp/Application/res/values-sw600dp/template-styles.xml b/samples/browseable/WearVerifyRemoteApp/Application/res/values-sw600dp/template-styles.xml
new file mode 100644
index 000000000..03d197418
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/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/samples/browseable/WearVerifyRemoteApp/Application/res/values-v11/template-styles.xml b/samples/browseable/WearVerifyRemoteApp/Application/res/values-v11/template-styles.xml
new file mode 100644
index 000000000..8c1ea66f2
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/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/samples/browseable/WearVerifyRemoteApp/Application/res/values-v21/base-colors.xml b/samples/browseable/WearVerifyRemoteApp/Application/res/values-v21/base-colors.xml
new file mode 100644
index 000000000..8b6ec3f85
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/res/values-v21/base-colors.xml
@@ -0,0 +1,21 @@
+<?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/samples/browseable/WearVerifyRemoteApp/Application/res/values-v21/base-template-styles.xml b/samples/browseable/WearVerifyRemoteApp/Application/res/values-v21/base-template-styles.xml
new file mode 100644
index 000000000..c778e4f98
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/res/values-v21/base-template-styles.xml
@@ -0,0 +1,24 @@
+<?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/samples/browseable/WearVerifyRemoteApp/Application/res/values/base-strings.xml b/samples/browseable/WearVerifyRemoteApp/Application/res/values/base-strings.xml
new file mode 100644
index 000000000..906f8f44a
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/res/values/base-strings.xml
@@ -0,0 +1,31 @@
+<?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">WearVerifyRemoteApp</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+Sample demonstrates best practices for checking if the remote version of your app is installed on a
+connected device. This enables standalone Android Wear apps to check if the phone app is installed
+and the other way around.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/WearVerifyRemoteApp/Application/res/values/colors.xml b/samples/browseable/WearVerifyRemoteApp/Application/res/values/colors.xml
new file mode 100644
index 000000000..e1632c558
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/res/values/colors.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources>
+ <color name="colorPrimary">#3F51B5</color>
+ <color name="colorPrimaryDark">#303F9F</color>
+ <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/samples/browseable/WearVerifyRemoteApp/Application/res/values/dimens.xml b/samples/browseable/WearVerifyRemoteApp/Application/res/values/dimens.xml
new file mode 100644
index 000000000..bc0615c75
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/res/values/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/samples/browseable/WearVerifyRemoteApp/Application/res/values/styles.xml b/samples/browseable/WearVerifyRemoteApp/Application/res/values/styles.xml
new file mode 100644
index 000000000..996e5b686
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/res/values/styles.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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>
+
+ <!-- Base application theme. -->
+ <style name="AppThemeCustom" parent="Theme.AppCompat.Light.DarkActionBar">
+ <!-- Customize your theme here. -->
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/WearVerifyRemoteApp/Application/res/values/template-dimens.xml b/samples/browseable/WearVerifyRemoteApp/Application/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/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/samples/browseable/WearVerifyRemoteApp/Application/res/values/template-styles.xml b/samples/browseable/WearVerifyRemoteApp/Application/res/values/template-styles.xml
new file mode 100644
index 000000000..6e7d593dd
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/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/samples/browseable/WearVerifyRemoteApp/Application/res/values/wear.xml b/samples/browseable/WearVerifyRemoteApp/Application/res/values/wear.xml
new file mode 100644
index 000000000..bcaf684f7
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/res/values/wear.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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="android_wear_capabilities">
+ <!-- IMPORTANT NOTE: Should be different than capability in Wear res/values/wear.xml. -->
+ <item>verify_remote_example_phone_app</item>
+ </string-array>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/WearVerifyRemoteApp/Application/src/com.example.android.wearable.wear.wearverifyremoteapp/MainMobileActivity.java b/samples/browseable/WearVerifyRemoteApp/Application/src/com.example.android.wearable.wear.wearverifyremoteapp/MainMobileActivity.java
new file mode 100644
index 000000000..ed1511936
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Application/src/com.example.android.wearable.wear.wearverifyremoteapp/MainMobileActivity.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2016 Google Inc. All Rights Reserved.
+ *
+ * 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.wearable.wear.wearverifyremoteapp;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.common.api.PendingResult;
+import com.google.android.gms.common.api.ResultCallback;
+import com.google.android.gms.wearable.CapabilityApi;
+import com.google.android.gms.wearable.CapabilityInfo;
+import com.google.android.gms.wearable.Node;
+import com.google.android.gms.wearable.NodeApi;
+import com.google.android.gms.wearable.Wearable;
+import com.google.android.wearable.intent.RemoteIntent;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Checks if the sample's Wear app is installed on remote Wear device(s). If it is not, allows the
+ * user to open the app listing on the Wear devices' Play Store.
+ */
+public class MainMobileActivity extends AppCompatActivity implements
+ GoogleApiClient.ConnectionCallbacks,
+ GoogleApiClient.OnConnectionFailedListener,
+ CapabilityApi.CapabilityListener {
+
+ private static final String TAG = "MainMobileActivity";
+
+ private static final String WELCOME_MESSAGE = "Welcome to our Mobile app!\n\n";
+
+ private static final String CHECKING_MESSAGE =
+ WELCOME_MESSAGE + "Checking for Wear Devices for app...\n";
+
+ private static final String NO_DEVICES =
+ WELCOME_MESSAGE
+ + "You have no Wear devices linked to your phone at this time.\n";
+
+ private static final String MISSING_ALL_MESSAGE =
+ WELCOME_MESSAGE
+ + "You are missing the Wear app on all your Wear Devices, please click on the "
+ + "button below to install it on those device(s).\n";
+
+ private static final String INSTALLED_SOME_DEVICES_MESSAGE =
+ WELCOME_MESSAGE
+ + "Wear app installed on some your device(s) (%s)!\n\nYou can now use the "
+ + "MessageApi, DataApi, etc.\n\n"
+ + "To install the Wear app on the other devices, please click on the button "
+ + "below.\n";
+
+ private static final String INSTALLED_ALL_DEVICES_MESSAGE =
+ WELCOME_MESSAGE
+ + "Wear app installed on all your devices (%s)!\n\nYou can now use the "
+ + "MessageApi, DataApi, etc.";
+
+ // Name of capability listed in Wear app's wear.xml.
+ // IMPORTANT NOTE: This should be named differently than your Phone app's capability.
+ private static final String CAPABILITY_WEAR_APP = "verify_remote_example_wear_app";
+
+ // Links to Wear app (Play Store).
+ // TODO: Replace with your links/packages.
+ private static final String PLAY_STORE_APP_URI =
+ "market://details?id=com.example.android.wearable.wear.wearverifyremoteapp";
+
+ // Result from sending RemoteIntent to wear device(s) to open app in play/app store.
+ private final ResultReceiver mResultReceiver = new ResultReceiver(new Handler()) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ Log.d(TAG, "onReceiveResult: " + resultCode);
+
+ if (resultCode == RemoteIntent.RESULT_OK) {
+ Toast toast = Toast.makeText(
+ getApplicationContext(),
+ "Play Store Request to Wear device successful.",
+ Toast.LENGTH_SHORT);
+ toast.show();
+
+ } else if (resultCode == RemoteIntent.RESULT_FAILED) {
+ Toast toast = Toast.makeText(
+ getApplicationContext(),
+ "Play Store Request Failed. Wear device(s) may not support Play Store, "
+ + " that is, the Wear device may be version 1.0.",
+ Toast.LENGTH_LONG);
+ toast.show();
+
+ } else {
+ throw new IllegalStateException("Unexpected result " + resultCode);
+ }
+ }
+ };
+
+ private TextView mInformationTextView;
+ private Button mRemoteOpenButton;
+
+ private Set<Node> mWearNodesWithApp;
+ private List<Node> mAllConnectedNodes;
+
+ private GoogleApiClient mGoogleApiClient;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ Log.d(TAG, "onCreate()");
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ mInformationTextView = (TextView) findViewById(R.id.information_text_view);
+ mRemoteOpenButton = (Button) findViewById(R.id.remote_open_button);
+
+ mInformationTextView.setText(CHECKING_MESSAGE);
+
+ mRemoteOpenButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ openPlayStoreOnWearDevicesWithoutApp();
+ }
+ });
+
+ mGoogleApiClient = new GoogleApiClient.Builder(this)
+ .addApi(Wearable.API)
+ .addConnectionCallbacks(this)
+ .addOnConnectionFailedListener(this)
+ .build();
+ }
+
+
+ @Override
+ protected void onPause() {
+ Log.d(TAG, "onPause()");
+ super.onPause();
+
+ if ((mGoogleApiClient != null) && mGoogleApiClient.isConnected()) {
+
+ Wearable.CapabilityApi.removeCapabilityListener(
+ mGoogleApiClient,
+ this,
+ CAPABILITY_WEAR_APP);
+
+ mGoogleApiClient.disconnect();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ Log.d(TAG, "onResume()");
+ super.onResume();
+ if (mGoogleApiClient != null) {
+ mGoogleApiClient.connect();
+ }
+ }
+
+ @Override
+ public void onConnected(@Nullable Bundle bundle) {
+ Log.d(TAG, "onConnected()");
+
+ // Set up listeners for capability changes (install/uninstall of remote app).
+ Wearable.CapabilityApi.addCapabilityListener(
+ mGoogleApiClient,
+ this,
+ CAPABILITY_WEAR_APP);
+
+ // Initial request for devices with our capability, aka, our Wear app installed.
+ findWearDevicesWithApp();
+
+ // Initial request for all Wear devices connected (with or without our capability).
+ // Additional Note: Because there isn't a listener for ALL Nodes added/removed from network
+ // that isn't deprecated, we simply update the full list when the Google API Client is
+ // connected and when capability changes come through in the onCapabilityChanged() method.
+ findAllWearDevices();
+ }
+
+ @Override
+ public void onConnectionSuspended(int i) {
+ Log.d(TAG, "onConnectionSuspended(): connection to location client suspended: " + i);
+ }
+
+ @Override
+ public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
+ Log.e(TAG, "onConnectionFailed(): " + connectionResult);
+ }
+
+ /*
+ * Updates UI when capabilities change (install/uninstall wear app).
+ */
+ public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
+ Log.d(TAG, "onCapabilityChanged(): " + capabilityInfo);
+
+ mWearNodesWithApp = capabilityInfo.getNodes();
+
+ // Because we have an updated list of devices with/without our app, we need to also update
+ // our list of active Wear devices.
+ findAllWearDevices();
+
+ verifyNodeAndUpdateUI();
+ }
+
+ private void findWearDevicesWithApp() {
+ Log.d(TAG, "findWearDevicesWithApp()");
+
+ // You can filter this by FILTER_REACHABLE if you only want to open Nodes (Wear Devices)
+ // directly connect to your phone.
+ PendingResult<CapabilityApi.GetCapabilityResult> pendingResult =
+ Wearable.CapabilityApi.getCapability(
+ mGoogleApiClient,
+ CAPABILITY_WEAR_APP,
+ CapabilityApi.FILTER_ALL);
+
+ pendingResult.setResultCallback(new ResultCallback<CapabilityApi.GetCapabilityResult>() {
+ @Override
+ public void onResult(@NonNull CapabilityApi.GetCapabilityResult getCapabilityResult) {
+ Log.d(TAG, "onResult(): " + getCapabilityResult);
+
+ if (getCapabilityResult.getStatus().isSuccess()) {
+ CapabilityInfo capabilityInfo = getCapabilityResult.getCapability();
+ mWearNodesWithApp = capabilityInfo.getNodes();
+ verifyNodeAndUpdateUI();
+
+ } else {
+ Log.d(TAG, "Failed CapabilityApi: " + getCapabilityResult.getStatus());
+ }
+ }
+ });
+ }
+
+ private void findAllWearDevices() {
+ Log.d(TAG, "findAllWearDevices()");
+
+ PendingResult<NodeApi.GetConnectedNodesResult> pendingResult =
+ Wearable.NodeApi.getConnectedNodes(mGoogleApiClient);
+
+ pendingResult.setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>() {
+ @Override
+ public void onResult(@NonNull NodeApi.GetConnectedNodesResult getConnectedNodesResult) {
+
+ if (getConnectedNodesResult.getStatus().isSuccess()) {
+ mAllConnectedNodes = getConnectedNodesResult.getNodes();
+ verifyNodeAndUpdateUI();
+
+ } else {
+ Log.d(TAG, "Failed CapabilityApi: " + getConnectedNodesResult.getStatus());
+ }
+ }
+ });
+ }
+
+ private void verifyNodeAndUpdateUI() {
+ Log.d(TAG, "verifyNodeAndUpdateUI()");
+
+ if ((mWearNodesWithApp == null) || (mAllConnectedNodes == null)) {
+ Log.d(TAG, "Waiting on Results for both connected nodes and nodes with app");
+
+ } else if (mAllConnectedNodes.isEmpty()) {
+ Log.d(TAG, NO_DEVICES);
+ mInformationTextView.setText(NO_DEVICES);
+ mRemoteOpenButton.setVisibility(View.INVISIBLE);
+
+ } else if (mWearNodesWithApp.isEmpty()) {
+ Log.d(TAG, MISSING_ALL_MESSAGE);
+ mInformationTextView.setText(MISSING_ALL_MESSAGE);
+ mRemoteOpenButton.setVisibility(View.VISIBLE);
+
+ } else if (mWearNodesWithApp.size() < mAllConnectedNodes.size()) {
+ // TODO: Add your code to communicate with the wear app(s) via
+ // Wear APIs (MessageApi, DataApi, etc.)
+
+ String installMessage =
+ String.format(INSTALLED_SOME_DEVICES_MESSAGE, mWearNodesWithApp);
+ Log.d(TAG, installMessage);
+ mInformationTextView.setText(installMessage);
+ mRemoteOpenButton.setVisibility(View.VISIBLE);
+
+ } else {
+ // TODO: Add your code to communicate with the wear app(s) via
+ // Wear APIs (MessageApi, DataApi, etc.)
+
+ String installMessage =
+ String.format(INSTALLED_ALL_DEVICES_MESSAGE, mWearNodesWithApp);
+ Log.d(TAG, installMessage);
+ mInformationTextView.setText(installMessage);
+ mRemoteOpenButton.setVisibility(View.INVISIBLE);
+
+ }
+ }
+
+ private void openPlayStoreOnWearDevicesWithoutApp() {
+ Log.d(TAG, "openPlayStoreOnWearDevicesWithoutApp()");
+
+ // Create a List of Nodes (Wear devices) without your app.
+ ArrayList<Node> nodesWithoutApp = new ArrayList<>();
+
+ for (Node node : mAllConnectedNodes) {
+ if (!mWearNodesWithApp.contains(node)) {
+ nodesWithoutApp.add(node);
+ }
+ }
+
+ if (!nodesWithoutApp.isEmpty()) {
+ Log.d(TAG, "Number of nodes without app: " + nodesWithoutApp.size());
+
+ Intent intent =
+ new Intent(Intent.ACTION_VIEW)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .setData(Uri.parse(PLAY_STORE_APP_URI));
+
+ for (Node node : nodesWithoutApp) {
+ RemoteIntent.startRemoteActivity(
+ getApplicationContext(),
+ intent,
+ mResultReceiver,
+ node.getId());
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/WearVerifyRemoteApp/Wearable/AndroidManifest.xml b/samples/browseable/WearVerifyRemoteApp/Wearable/AndroidManifest.xml
new file mode 100644
index 000000000..ee3f2dc11
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Wearable/AndroidManifest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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 package="com.example.android.wearable.wear.wearverifyremoteapp"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-feature android:name="android.hardware.type.watch"/>
+ <!-- Required for Always-on. -->
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
+
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:supportsRtl="true"
+ android:theme="@android:style/Theme.DeviceDefault">
+
+ <meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="true" />
+
+ <!--If you want your app to run on pre-22, then set required to false -->
+ <uses-library android:name="com.google.android.wearable" android:required="false" />
+
+ <activity
+ android:name=".MainWearActivity"
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.DeviceDefault.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+
+ </application>
+</manifest> \ No newline at end of file
diff --git a/samples/browseable/WearVerifyRemoteApp/Wearable/res/layout/activity_main.xml b/samples/browseable/WearVerifyRemoteApp/Wearable/res/layout/activity_main.xml
new file mode 100644
index 000000000..3a997745b
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Wearable/res/layout/activity_main.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingTop="@dimen/activity_main_top_padding"
+ android:paddingRight="@dimen/activity_main_right_padding"
+ android:paddingLeft="@dimen/activity_main_left_padding"
+ android:paddingBottom="@dimen/activity_main_bottom_padding"
+ tools:context="com.example.android.wearable.wear.wearverifyremoteapp.MainWearActivity">
+
+ <TextView
+ android:id="@+id/information_text_view"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="3"/>
+
+ <Button
+ android:id="@+id/remote_open_button"
+ android:layout_width="match_parent"
+ android:text="Install Mobile App"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:visibility="invisible"/>
+</LinearLayout> \ No newline at end of file
diff --git a/samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-hdpi/ic_launcher.png b/samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..cde69bccc
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-mdpi/ic_launcher.png b/samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..c133a0cbd
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-xhdpi/ic_launcher.png b/samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..bfa42f0e7
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-xxhdpi/ic_launcher.png b/samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..324e72cdd
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Wearable/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/WearVerifyRemoteApp/Wearable/res/values-round/dimens.xml b/samples/browseable/WearVerifyRemoteApp/Wearable/res/values-round/dimens.xml
new file mode 100644
index 000000000..b0152cd7e
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Wearable/res/values-round/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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="activity_main_top_padding">36dp</dimen>
+ <dimen name="activity_main_bottom_padding">22dp</dimen>
+ <dimen name="activity_main_right_padding">36dp</dimen>
+ <dimen name="activity_main_left_padding">36dp</dimen>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/WearVerifyRemoteApp/Wearable/res/values/dimens.xml b/samples/browseable/WearVerifyRemoteApp/Wearable/res/values/dimens.xml
new file mode 100644
index 000000000..cacdaf3f5
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Wearable/res/values/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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="activity_main_top_padding">5dp</dimen>
+ <dimen name="activity_main_bottom_padding">5dp</dimen>
+ <dimen name="activity_main_right_padding">5dp</dimen>
+ <dimen name="activity_main_left_padding">5dp</dimen>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/WearVerifyRemoteApp/Wearable/res/values/strings.xml b/samples/browseable/WearVerifyRemoteApp/Wearable/res/values/strings.xml
new file mode 100644
index 000000000..65c4ea573
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Wearable/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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">Wear Verify Remote App</string>
+</resources>
diff --git a/samples/browseable/WearVerifyRemoteApp/Wearable/res/values/wear.xml b/samples/browseable/WearVerifyRemoteApp/Wearable/res/values/wear.xml
new file mode 100644
index 000000000..584747ba7
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Wearable/res/values/wear.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016 Google Inc.
+ ~
+ ~ 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="android_wear_capabilities">
+ <!-- IMPORTANT NOTE: Should be different than capability in App res/values/wear.xml. -->
+ <item>verify_remote_example_wear_app</item>
+ </string-array>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/WearVerifyRemoteApp/Wearable/src/com.example.android.wearable.wear.wearverifyremoteapp/MainWearActivity.java b/samples/browseable/WearVerifyRemoteApp/Wearable/src/com.example.android.wearable.wear.wearverifyremoteapp/MainWearActivity.java
new file mode 100644
index 000000000..31882b0b1
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/Wearable/src/com.example.android.wearable.wear.wearverifyremoteapp/MainWearActivity.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2016 Google Inc. All Rights Reserved.
+ *
+ * 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.wearable.wear.wearverifyremoteapp;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.wearable.activity.WearableActivity;
+import android.support.wearable.view.ConfirmationOverlay;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.common.api.PendingResult;
+import com.google.android.gms.common.api.ResultCallback;
+import com.google.android.gms.wearable.CapabilityApi;
+import com.google.android.gms.wearable.CapabilityInfo;
+import com.google.android.gms.wearable.Node;
+import com.google.android.gms.wearable.Wearable;
+import com.google.android.wearable.intent.RemoteIntent;
+import com.google.android.wearable.playstore.PlayStoreAvailability;
+
+import java.util.Set;
+
+/**
+ * Checks if the phone app is installed on remote device. If it is not, allows user to open app
+ * listing on the phone's Play or App Store.
+ */
+public class MainWearActivity extends WearableActivity implements
+ GoogleApiClient.ConnectionCallbacks,
+ GoogleApiClient.OnConnectionFailedListener,
+ CapabilityApi.CapabilityListener {
+
+ private static final String TAG = "MainWearActivity";
+
+ private static final String WELCOME_MESSAGE = "Welcome to our Wear app!\n\n";
+
+ private static final String CHECKING_MESSAGE =
+ WELCOME_MESSAGE + "Checking for Mobile app...\n";
+
+ private static final String MISSING_MESSAGE =
+ WELCOME_MESSAGE
+ + "You are missing the required phone app, please click on the button below to "
+ + "install it on your phone.\n";
+
+ private static final String INSTALLED_MESSAGE =
+ WELCOME_MESSAGE
+ + "Mobile app installed on your %s!\n\nYou can now use MessageApi, "
+ + "DataApi, etc.";
+
+ // Name of capability listed in Phone app's wear.xml.
+ // IMPORTANT NOTE: This should be named differently than your Wear app's capability.
+ private static final String CAPABILITY_PHONE_APP = "verify_remote_example_phone_app";
+
+ // Links to install mobile app for both Android (Play Store) and iOS.
+ // TODO: Replace with your links/packages.
+ private static final String PLAY_STORE_APP_URI =
+ "market://details?id=com.example.android.wearable.wear.wearverifyremoteapp";
+
+ // TODO: Replace with your links/packages.
+ private static final String APP_STORE_APP_URI =
+ "https://itunes.apple.com/us/app/android-wear/id986496028?mt=8";
+
+ // Result from sending RemoteIntent to phone to open app in play/app store.
+ private final ResultReceiver mResultReceiver = new ResultReceiver(new Handler()) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+
+ if (resultCode == RemoteIntent.RESULT_OK) {
+ new ConfirmationOverlay().showOn(MainWearActivity.this);
+
+ } else if (resultCode == RemoteIntent.RESULT_FAILED) {
+ new ConfirmationOverlay()
+ .setType(ConfirmationOverlay.FAILURE_ANIMATION)
+ .showOn(MainWearActivity.this);
+
+ } else {
+ throw new IllegalStateException("Unexpected result " + resultCode);
+ }
+ }
+ };
+
+ private TextView mInformationTextView;
+ private Button mRemoteOpenButton;
+
+ private Node mAndroidPhoneNodeWithApp;
+
+ private GoogleApiClient mGoogleApiClient;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ Log.d(TAG, "onCreate()");
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.activity_main);
+ setAmbientEnabled();
+
+ mInformationTextView = (TextView) findViewById(R.id.information_text_view);
+ mRemoteOpenButton = (Button) findViewById(R.id.remote_open_button);
+
+ mInformationTextView.setText(CHECKING_MESSAGE);
+
+ mRemoteOpenButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ openAppInStoreOnPhone();
+ }
+ });
+
+ mGoogleApiClient = new GoogleApiClient.Builder(this)
+ .addApi(Wearable.API)
+ .addConnectionCallbacks(this)
+ .addOnConnectionFailedListener(this)
+ .build();
+ }
+
+
+ @Override
+ protected void onPause() {
+ Log.d(TAG, "onPause()");
+ super.onPause();
+
+ if ((mGoogleApiClient != null) && mGoogleApiClient.isConnected()) {
+ Wearable.CapabilityApi.removeCapabilityListener(
+ mGoogleApiClient,
+ this,
+ CAPABILITY_PHONE_APP);
+
+ mGoogleApiClient.disconnect();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ Log.d(TAG, "onResume()");
+ super.onResume();
+ if (mGoogleApiClient != null) {
+ mGoogleApiClient.connect();
+ }
+ }
+
+ @Override
+ public void onConnected(@Nullable Bundle bundle) {
+ Log.d(TAG, "onConnected()");
+
+ // Set up listeners for capability changes (install/uninstall of remote app).
+ Wearable.CapabilityApi.addCapabilityListener(
+ mGoogleApiClient,
+ this,
+ CAPABILITY_PHONE_APP);
+
+ checkIfPhoneHasApp();
+ }
+
+ @Override
+ public void onConnectionSuspended(int i) {
+ Log.d(TAG, "onConnectionSuspended(): connection to location client suspended: " + i);
+ }
+
+ @Override
+ public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
+ Log.e(TAG, "onConnectionFailed(): " + connectionResult);
+ }
+
+ /*
+ * Updates UI when capabilities change (install/uninstall phone app).
+ */
+ public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
+ Log.d(TAG, "onCapabilityChanged(): " + capabilityInfo);
+
+ mAndroidPhoneNodeWithApp = pickBestNodeId(capabilityInfo.getNodes());
+ verifyNodeAndUpdateUI();
+ }
+
+ private void checkIfPhoneHasApp() {
+ Log.d(TAG, "checkIfPhoneHasApp()");
+
+ PendingResult<CapabilityApi.GetCapabilityResult> pendingResult =
+ Wearable.CapabilityApi.getCapability(
+ mGoogleApiClient,
+ CAPABILITY_PHONE_APP,
+ CapabilityApi.FILTER_ALL);
+
+ pendingResult.setResultCallback(new ResultCallback<CapabilityApi.GetCapabilityResult>() {
+
+ @Override
+ public void onResult(@NonNull CapabilityApi.GetCapabilityResult getCapabilityResult) {
+ Log.d(TAG, "onResult(): " + getCapabilityResult);
+
+ if (getCapabilityResult.getStatus().isSuccess()) {
+ CapabilityInfo capabilityInfo = getCapabilityResult.getCapability();
+ mAndroidPhoneNodeWithApp = pickBestNodeId(capabilityInfo.getNodes());
+ verifyNodeAndUpdateUI();
+
+ } else {
+ Log.d(TAG, "Failed CapabilityApi: " + getCapabilityResult.getStatus());
+ }
+ }
+ });
+ }
+
+ private void verifyNodeAndUpdateUI() {
+
+ if (mAndroidPhoneNodeWithApp != null) {
+
+ // TODO: Add your code to communicate with the phone app via
+ // Wear APIs (MessageApi, DataApi, etc.)
+
+ String installMessage =
+ String.format(INSTALLED_MESSAGE, mAndroidPhoneNodeWithApp.getDisplayName());
+ Log.d(TAG, installMessage);
+ mInformationTextView.setText(installMessage);
+ mRemoteOpenButton.setVisibility(View.INVISIBLE);
+
+ } else {
+ Log.d(TAG, MISSING_MESSAGE);
+ mInformationTextView.setText(MISSING_MESSAGE);
+ mRemoteOpenButton.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void openAppInStoreOnPhone() {
+ Log.d(TAG, "openAppInStoreOnPhone()");
+
+ int playStoreAvailabilityOnPhone =
+ PlayStoreAvailability.getPlayStoreAvailabilityOnPhone(getApplicationContext());
+
+ switch (playStoreAvailabilityOnPhone) {
+
+ // Android phone with the Play Store.
+ case PlayStoreAvailability.PLAY_STORE_ON_PHONE_AVAILABLE:
+ Log.d(TAG, "\tPLAY_STORE_ON_PHONE_AVAILABLE");
+
+ // Create Remote Intent to open Play Store listing of app on remote device.
+ Intent intentAndroid =
+ new Intent(Intent.ACTION_VIEW)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .setData(Uri.parse(PLAY_STORE_APP_URI));
+
+ RemoteIntent.startRemoteActivity(
+ getApplicationContext(),
+ intentAndroid,
+ mResultReceiver);
+ break;
+
+ // Assume iPhone (iOS device) or Android without Play Store (not supported right now).
+ case PlayStoreAvailability.PLAY_STORE_ON_PHONE_UNAVAILABLE:
+ Log.d(TAG, "\tPLAY_STORE_ON_PHONE_UNAVAILABLE");
+
+ // Create Remote Intent to open App Store listing of app on iPhone.
+ Intent intentIOS =
+ new Intent(Intent.ACTION_VIEW)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .setData(Uri.parse(APP_STORE_APP_URI));
+
+ RemoteIntent.startRemoteActivity(
+ getApplicationContext(),
+ intentIOS,
+ mResultReceiver);
+ break;
+
+ case PlayStoreAvailability.PLAY_STORE_ON_PHONE_ERROR_UNKNOWN:
+ Log.d(TAG, "\tPLAY_STORE_ON_PHONE_ERROR_UNKNOWN");
+ break;
+ }
+ }
+
+ /*
+ * There should only ever be one phone in a node set (much less w/ the correct capability), so
+ * I am just grabbing the first one (which should be the only one).
+ */
+ private Node pickBestNodeId(Set<Node> nodes) {
+ Log.d(TAG, "pickBestNodeId(): " + nodes);
+
+ Node bestNodeId = null;
+ // Find a nearby node/phone or pick one arbitrarily. Realistically, there is only one phone.
+ for (Node node : nodes) {
+ bestNodeId = node;
+ }
+ return bestNodeId;
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/WearVerifyRemoteApp/_index.jd b/samples/browseable/WearVerifyRemoteApp/_index.jd
new file mode 100644
index 000000000..f9fb5f861
--- /dev/null
+++ b/samples/browseable/WearVerifyRemoteApp/_index.jd
@@ -0,0 +1,12 @@
+
+page.tags="WearVerifyRemoteApp"
+sample.group=Wearable
+@jd:body
+
+<p>
+
+Sample demonstrates best practices for checking if the remote version of your app is installed on a
+connected device. This enables standalone Android Wear apps to check if the phone app is installed
+and the other way around.
+
+ </p>
diff --git a/samples/browseable/XYZTouristAttractions/Wearable/AndroidManifest.xml b/samples/browseable/XYZTouristAttractions/Wearable/AndroidManifest.xml
index fc086da1a..320396db5 100644
--- a/samples/browseable/XYZTouristAttractions/Wearable/AndroidManifest.xml
+++ b/samples/browseable/XYZTouristAttractions/Wearable/AndroidManifest.xml
@@ -25,8 +25,8 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove" />
<uses-sdk
- android:minSdkVersion="21"
- android:targetSdkVersion="22" />
+ android:minSdkVersion="22"
+ android:targetSdkVersion="25" />
<application
android:allowBackup="true"
@@ -34,6 +34,10 @@
android:label="@string/app_name"
android:theme="@android:style/Theme.DeviceDefault" >
+ <meta-data
+ android:name="com.google.android.wearable.standalone"
+ android:value="false" />
+
<activity
android:name=".ui.AttractionsActivity"
android:label="@string/app_name" />
diff --git a/samples/samples_source.prop_template b/samples/samples_source.prop_template
index d3cdfd5ee..523d6bda8 100644
--- a/samples/samples_source.prop_template
+++ b/samples/samples_source.prop_template
@@ -1,4 +1,4 @@
Pkg.UserSrc=false
-Pkg.Revision=1
+Pkg.Revision=2
AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
diff --git a/testrunner/test_defs.xml b/testrunner/test_defs.xml
index d475889f1..4a1868ad4 100644
--- a/testrunner/test_defs.xml
+++ b/testrunner/test_defs.xml
@@ -71,6 +71,7 @@ See test_defs.xsd for more information.
<test name="frameworks-telephony"
build_path="frameworks/opt/telephony/tests/telephonytests"
package="com.android.frameworks.telephonytests"
+ runner="android.support.test.runner.AndroidJUnitRunner"
coverage_target="framework"
continuous="true" />