summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk3
-rw-r--r--AndroidManifest.xml26
-rw-r--r--res/drawable-watch-280dpi/ic_cc_cancel.pngbin0 -> 14774 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_cc_checkmark.pngbin0 -> 14840 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_cc_deny.pngbin0 -> 18879 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_calendar.pngbin0 -> 20425 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_calendardisable.pngbin0 -> 18888 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_call.pngbin0 -> 20029 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_calldisable.pngbin0 -> 18813 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_camera.pngbin0 -> 20572 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_cameradisable.pngbin0 -> 18391 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_contact.pngbin0 -> 19960 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_contactdisable.pngbin0 -> 18921 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_location.pngbin0 -> 19625 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_locationdisable.pngbin0 -> 18803 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_mic.pngbin0 -> 20006 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_micdisable.pngbin0 -> 20179 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_more.pngbin0 -> 19946 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_sensor.pngbin0 -> 20622 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_sensordisable.pngbin0 -> 20391 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_shield.pngbin0 -> 20403 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_shielddisable.pngbin0 -> 19978 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_sms.pngbin0 -> 20341 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_smsdisable.pngbin0 -> 20159 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_storage.pngbin0 -> 19814 bytes
-rw-r--r--res/drawable-watch-280dpi/ic_permission_storagedisable.pngbin0 -> 20135 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_cc_cancel.pngbin0 -> 678 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_cc_checkmark.pngbin0 -> 646 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_cc_deny.pngbin0 -> 923 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_calendar.pngbin0 -> 760 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_calendardisable.pngbin0 -> 987 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_call.pngbin0 -> 808 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_calldisable.pngbin0 -> 940 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_camera.pngbin0 -> 676 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_cameradisable.pngbin0 -> 979 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_contact.pngbin0 -> 717 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_contactdisable.pngbin0 -> 989 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_location.pngbin0 -> 804 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_locationdisable.pngbin0 -> 932 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_mic.pngbin0 -> 731 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_micdisable.pngbin0 -> 911 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_more.pngbin0 -> 579 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_sensor.pngbin0 -> 911 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_sensordisable.pngbin0 -> 1034 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_shield.pngbin0 -> 751 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_shielddisable.pngbin0 -> 896 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_sms.pngbin0 -> 643 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_smsdisable.pngbin0 -> 823 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_storage.pngbin0 -> 523 bytes
-rw-r--r--res/drawable-watch-hdpi/ic_permission_storagedisable.pngbin0 -> 751 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_cc_cancel.pngbin0 -> 535 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_cc_checkmark.pngbin0 -> 509 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_cc_deny.pngbin0 -> 661 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_calendar.pngbin0 -> 608 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_calendardisable.pngbin0 -> 708 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_call.pngbin0 -> 599 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_calldisable.pngbin0 -> 690 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_camera.pngbin0 -> 539 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_cameradisable.pngbin0 -> 691 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_contact.pngbin0 -> 566 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_contactdisable.pngbin0 -> 686 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_location.pngbin0 -> 586 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_locationdisable.pngbin0 -> 673 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_mic.pngbin0 -> 561 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_micdisable.pngbin0 -> 638 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_more.pngbin0 -> 441 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_sensor.pngbin0 -> 635 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_sensordisable.pngbin0 -> 713 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_shield.pngbin0 -> 562 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_shielddisable.pngbin0 -> 652 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_sms.pngbin0 -> 561 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_smsdisable.pngbin0 -> 671 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_storage.pngbin0 -> 471 bytes
-rw-r--r--res/drawable-watch-mdpi/ic_permission_storagedisable.pngbin0 -> 603 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_cc_cancel.pngbin0 -> 312 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_cc_checkmark.pngbin0 -> 321 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_cc_deny.pngbin0 -> 18778 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_calendar.pngbin0 -> 19782 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_calendardisable.pngbin0 -> 18211 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_call.pngbin0 -> 19995 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_calldisable.pngbin0 -> 18621 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_camera.pngbin0 -> 20027 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_cameradisable.pngbin0 -> 18391 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_contact.pngbin0 -> 19471 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_contactdisable.pngbin0 -> 18283 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_location.pngbin0 -> 19625 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_locationdisable.pngbin0 -> 18292 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_mic.pngbin0 -> 19554 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_micdisable.pngbin0 -> 19609 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_more.pngbin0 -> 19547 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_sensor.pngbin0 -> 20118 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_sensordisable.pngbin0 -> 19703 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_shield.pngbin0 -> 19931 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_shielddisable.pngbin0 -> 19978 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_sms.pngbin0 -> 19807 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_smsdisable.pngbin0 -> 19499 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_storage.pngbin0 -> 19295 bytes
-rw-r--r--res/drawable-watch-xhdpi/ic_permission_storagedisable.pngbin0 -> 19443 bytes
-rw-r--r--res/drawable-watch/action_negative_bg.xml35
-rw-r--r--res/drawable-watch/action_positive_bg.xml35
-rw-r--r--res/drawable-watch/cancel_button.xml21
-rw-r--r--res/drawable-watch/confirm_button.xml21
-rw-r--r--res/drawable-watch/deny_button.xml21
-rw-r--r--res/layout-watch/confirmation_dialog.xml131
-rw-r--r--res/layout-watch/permissions_settings_item.xml47
-rw-r--r--res/layout-watch/settings.xml21
-rw-r--r--res/layout-watch/settings_internal.xml37
-rw-r--r--res/values-af-watch/strings.xml25
-rw-r--r--res/values-af/strings.xml2
-rw-r--r--res/values-am-watch/strings.xml25
-rw-r--r--res/values-am/strings.xml2
-rw-r--r--res/values-ar-watch/strings.xml25
-rw-r--r--res/values-ar/strings.xml2
-rw-r--r--res/values-az-rAZ-watch/strings.xml25
-rw-r--r--res/values-az-rAZ/strings.xml2
-rw-r--r--res/values-bg-watch/strings.xml25
-rw-r--r--res/values-bg/strings.xml2
-rw-r--r--res/values-bn-rBD-watch/strings.xml25
-rw-r--r--res/values-bn-rBD/strings.xml2
-rw-r--r--res/values-ca-watch/strings.xml25
-rw-r--r--res/values-ca/strings.xml2
-rw-r--r--res/values-cs-watch/strings.xml25
-rw-r--r--res/values-cs/strings.xml2
-rw-r--r--res/values-da-watch/strings.xml25
-rw-r--r--res/values-da/strings.xml2
-rw-r--r--res/values-de-watch/strings.xml25
-rw-r--r--res/values-de/strings.xml2
-rw-r--r--res/values-el-watch/strings.xml25
-rw-r--r--res/values-el/strings.xml2
-rw-r--r--res/values-en-rAU-watch/strings.xml25
-rw-r--r--res/values-en-rAU/strings.xml2
-rw-r--r--res/values-en-rGB-watch/strings.xml25
-rw-r--r--res/values-en-rGB/strings.xml2
-rw-r--r--res/values-en-rIN-watch/strings.xml25
-rw-r--r--res/values-en-rIN/strings.xml2
-rw-r--r--res/values-es-rUS-watch/strings.xml25
-rw-r--r--res/values-es-rUS/strings.xml2
-rw-r--r--res/values-es-watch/strings.xml25
-rw-r--r--res/values-es/strings.xml2
-rw-r--r--res/values-et-rEE-watch/strings.xml25
-rw-r--r--res/values-et-rEE/strings.xml2
-rw-r--r--res/values-eu-rES-watch/strings.xml25
-rw-r--r--res/values-eu-rES/strings.xml2
-rw-r--r--res/values-fa-watch/strings.xml25
-rw-r--r--res/values-fa/strings.xml2
-rw-r--r--res/values-fi-watch/strings.xml25
-rw-r--r--res/values-fi/strings.xml2
-rw-r--r--res/values-fr-rCA-watch/strings.xml25
-rw-r--r--res/values-fr-rCA/strings.xml2
-rw-r--r--res/values-fr-watch/strings.xml25
-rw-r--r--res/values-fr/strings.xml2
-rw-r--r--res/values-gl-rES-watch/strings.xml25
-rw-r--r--res/values-gl-rES/strings.xml2
-rw-r--r--res/values-gu-rIN-watch/strings.xml25
-rw-r--r--res/values-gu-rIN/strings.xml2
-rw-r--r--res/values-hi-watch/strings.xml25
-rw-r--r--res/values-hi/strings.xml2
-rw-r--r--res/values-hr-watch/strings.xml25
-rw-r--r--res/values-hr/strings.xml2
-rw-r--r--res/values-hu-watch/strings.xml25
-rw-r--r--res/values-hu/strings.xml2
-rw-r--r--res/values-hy-rAM-watch/strings.xml25
-rw-r--r--res/values-hy-rAM/strings.xml2
-rw-r--r--res/values-in-watch/strings.xml25
-rw-r--r--res/values-in/strings.xml2
-rw-r--r--res/values-is-rIS-watch/strings.xml25
-rw-r--r--res/values-is-rIS/strings.xml2
-rw-r--r--res/values-it-watch/strings.xml25
-rw-r--r--res/values-it/strings.xml2
-rw-r--r--res/values-iw-watch/strings.xml25
-rw-r--r--res/values-iw/strings.xml2
-rw-r--r--res/values-ja-watch/strings.xml25
-rw-r--r--res/values-ja/strings.xml2
-rw-r--r--res/values-ka-rGE-watch/strings.xml25
-rw-r--r--res/values-ka-rGE/strings.xml2
-rw-r--r--res/values-kk-rKZ-watch/strings.xml25
-rw-r--r--res/values-kk-rKZ/strings.xml2
-rw-r--r--res/values-km-rKH-watch/strings.xml25
-rw-r--r--res/values-km-rKH/strings.xml2
-rw-r--r--res/values-kn-rIN-watch/strings.xml25
-rw-r--r--res/values-kn-rIN/strings.xml2
-rw-r--r--res/values-ko-watch/strings.xml25
-rw-r--r--res/values-ko/strings.xml2
-rw-r--r--res/values-ky-rKG-watch/strings.xml25
-rw-r--r--res/values-ky-rKG/strings.xml2
-rw-r--r--res/values-lo-rLA-watch/strings.xml25
-rw-r--r--res/values-lo-rLA/strings.xml2
-rw-r--r--res/values-lt-watch/strings.xml25
-rw-r--r--res/values-lt/strings.xml2
-rw-r--r--res/values-lv-watch/strings.xml25
-rw-r--r--res/values-lv/strings.xml2
-rw-r--r--res/values-mk-rMK-watch/strings.xml25
-rw-r--r--res/values-mk-rMK/strings.xml2
-rw-r--r--res/values-ml-rIN-watch/strings.xml25
-rw-r--r--res/values-ml-rIN/strings.xml2
-rw-r--r--res/values-mn-rMN-watch/strings.xml25
-rw-r--r--res/values-mn-rMN/strings.xml2
-rw-r--r--res/values-mr-rIN-watch/strings.xml25
-rw-r--r--res/values-mr-rIN/strings.xml2
-rw-r--r--res/values-ms-rMY-watch/strings.xml25
-rw-r--r--res/values-ms-rMY/strings.xml2
-rw-r--r--res/values-my-rMM-watch/strings.xml25
-rw-r--r--res/values-my-rMM/strings.xml2
-rw-r--r--res/values-nb-watch/strings.xml25
-rw-r--r--res/values-nb/strings.xml2
-rw-r--r--res/values-ne-rNP-watch/strings.xml25
-rw-r--r--res/values-ne-rNP/strings.xml2
-rw-r--r--res/values-nl-watch/strings.xml25
-rw-r--r--res/values-nl/strings.xml2
-rw-r--r--res/values-pa-rIN-watch/strings.xml25
-rw-r--r--res/values-pa-rIN/strings.xml2
-rw-r--r--res/values-pl-watch/strings.xml25
-rw-r--r--res/values-pl/strings.xml2
-rw-r--r--res/values-pt-rBR-watch/strings.xml25
-rw-r--r--res/values-pt-rBR/strings.xml2
-rw-r--r--res/values-pt-rPT-watch/strings.xml25
-rw-r--r--res/values-pt-rPT/strings.xml2
-rw-r--r--res/values-pt-watch/strings.xml25
-rw-r--r--res/values-pt/strings.xml2
-rw-r--r--res/values-ro-watch/strings.xml25
-rw-r--r--res/values-ro/strings.xml2
-rw-r--r--res/values-round/dimens.xml26
-rw-r--r--res/values-ru-watch/strings.xml25
-rw-r--r--res/values-ru/strings.xml2
-rw-r--r--res/values-si-rLK-watch/strings.xml25
-rw-r--r--res/values-si-rLK/strings.xml2
-rw-r--r--res/values-sk-watch/strings.xml25
-rw-r--r--res/values-sk/strings.xml2
-rw-r--r--res/values-sl-watch/strings.xml25
-rw-r--r--res/values-sl/strings.xml2
-rw-r--r--res/values-sq-rAL-watch/strings.xml25
-rw-r--r--res/values-sq-rAL/strings.xml2
-rw-r--r--res/values-sr-watch/strings.xml25
-rw-r--r--res/values-sr/strings.xml2
-rw-r--r--res/values-sv-watch/strings.xml25
-rw-r--r--res/values-sv/strings.xml2
-rw-r--r--res/values-sw-watch/strings.xml25
-rw-r--r--res/values-sw/strings.xml2
-rw-r--r--res/values-ta-rIN-watch/strings.xml25
-rw-r--r--res/values-ta-rIN/strings.xml2
-rw-r--r--res/values-te-rIN-watch/strings.xml25
-rw-r--r--res/values-te-rIN/strings.xml2
-rw-r--r--res/values-th-watch/strings.xml25
-rw-r--r--res/values-th/strings.xml2
-rw-r--r--res/values-tl-watch/strings.xml25
-rw-r--r--res/values-tl/strings.xml2
-rw-r--r--res/values-tr-watch/strings.xml25
-rw-r--r--res/values-tr/strings.xml2
-rw-r--r--res/values-uk-watch/strings.xml25
-rw-r--r--res/values-uk/strings.xml2
-rw-r--r--res/values-ur-rPK-watch/strings.xml25
-rw-r--r--res/values-ur-rPK/strings.xml2
-rw-r--r--res/values-uz-rUZ-watch/strings.xml25
-rw-r--r--res/values-uz-rUZ/strings.xml2
-rw-r--r--res/values-vi-watch/strings.xml25
-rw-r--r--res/values-vi/strings.xml2
-rw-r--r--res/values-watch/attrs.xml35
-rw-r--r--res/values-watch/colors.xml36
-rw-r--r--res/values-watch/dimens.xml57
-rw-r--r--res/values-watch/integers.xml22
-rw-r--r--res/values-watch/strings.xml37
-rw-r--r--res/values-watch/styles.xml49
-rw-r--r--res/values-watch/themes.xml64
-rw-r--r--res/values-zh-rCN-watch/strings.xml25
-rw-r--r--res/values-zh-rCN/strings.xml2
-rw-r--r--res/values-zh-rHK-watch/strings.xml25
-rw-r--r--res/values-zh-rHK/strings.xml2
-rw-r--r--res/values-zh-rTW-watch/strings.xml25
-rw-r--r--res/values-zh-rTW/strings.xml2
-rw-r--r--res/values-zu-watch/strings.xml25
-rw-r--r--res/values-zu/strings.xml2
-rw-r--r--res/values/strings.xml5
-rw-r--r--src/android/support/wearable/view/CircledImageView.java603
-rw-r--r--src/android/support/wearable/view/Gusterpolator.java84
-rw-r--r--src/android/support/wearable/view/ProgressDrawable.java176
-rw-r--r--src/android/support/wearable/view/SimpleAnimatorListener.java67
-rw-r--r--src/android/support/wearable/view/WearableListView.java1387
-rw-r--r--src/com/android/packageinstaller/DeviceUtils.java32
-rw-r--r--src/com/android/packageinstaller/InstallFlowAnalytics.java7
-rw-r--r--src/com/android/packageinstaller/PackageInstallerActivity.java22
-rw-r--r--src/com/android/packageinstaller/permission/model/AppPermissions.java9
-rw-r--r--src/com/android/packageinstaller/permission/model/PermissionStatusReceiver.java107
-rw-r--r--src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java5
-rw-r--r--src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java176
-rw-r--r--src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java6
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java3
-rw-r--r--src/com/android/packageinstaller/permission/ui/wear/AppPermissionsFragmentWear.java335
-rw-r--r--src/com/android/packageinstaller/permission/ui/wear/ConfirmationViewHandler.java381
-rw-r--r--src/com/android/packageinstaller/permission/ui/wear/TitledSettingsFragment.java234
-rw-r--r--src/com/android/packageinstaller/permission/ui/wear/WarningConfirmationActivity.java118
-rw-r--r--src/com/android/packageinstaller/permission/ui/wear/settings/ExtendedOnCenterProximityListener.java30
-rw-r--r--src/com/android/packageinstaller/permission/ui/wear/settings/ExtendedViewHolder.java84
-rw-r--r--src/com/android/packageinstaller/permission/ui/wear/settings/PermissionsSettingsAdapter.java101
-rw-r--r--src/com/android/packageinstaller/permission/ui/wear/settings/SettingsAdapter.java276
-rw-r--r--src/com/android/packageinstaller/permission/ui/wear/settings/ViewUtils.java48
-rw-r--r--src/com/android/packageinstaller/permission/utils/Utils.java21
-rw-r--r--src/com/android/packageinstaller/wear/WearPackageArgs.java92
-rw-r--r--src/com/android/packageinstaller/wear/WearPackageIconProvider.java202
-rw-r--r--src/com/android/packageinstaller/wear/WearPackageInstallerService.java602
-rw-r--r--src/com/android/packageinstaller/wear/WearPackageUtil.java167
300 files changed, 8177 insertions, 33 deletions
diff --git a/Android.mk b/Android.mk
index 5a53086e..4b2864ba 100644
--- a/Android.mk
+++ b/Android.mk
@@ -14,7 +14,8 @@ LOCAL_STATIC_JAVA_LIBRARIES += \
android-support-v7-appcompat \
android-support-v14-preference \
android-support-v17-preference-leanback \
- android-support-v17-leanback
+ android-support-v17-leanback \
+ xz-java
LOCAL_RESOURCE_DIR := \
frameworks/support/v17/leanback/res \
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9120e7ec..3f1bb1d8 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -16,8 +16,11 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.READ_INSTALL_SESSIONS" />
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.KILL_UID" />
+ <uses-permission android:name="com.google.android.permission.INSTALL_WEARABLE_PACKAGES" />
+
<application android:label="@string/app_name"
android:allowBackup="false"
android:theme="@style/Theme.DialogWhenLarge"
@@ -97,8 +100,31 @@
android:permission="android.permission.GRANT_RUNTIME_PERMISSIONS">
<intent-filter>
<action android:name="android.intent.action.GET_PERMISSIONS_COUNT" />
+ <action android:name="android.intent.action.GET_PERMISSIONS_PACKAGES" />
</intent-filter>
</receiver>
+
+ <!-- Wearable Components -->
+ <service android:name=".wear.WearPackageInstallerService"
+ android:permission="com.google.android.permission.INSTALL_WEARABLE_PACKAGES"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.packageinstaller.wear.INSTALL_PACKAGE"/>
+ <data android:scheme="content" android:mimeType="vnd.android.cursor.item/*"/>
+ </intent-filter>
+ <intent-filter>
+ <action android:name="com.android.packageinstaller.wear.UNINSTALL_PACKAGE"/>
+ </intent-filter>
+ </service>
+
+ <provider android:name=".wear.WearPackageIconProvider"
+ android:authorities="com.google.android.packageinstaller.wear.provider"
+ android:grantUriPermissions="true"
+ android:exported="true" />
+
+ <activity android:name=".permission.ui.wear.WarningConfirmationActivity"
+ android:permission="android.permission.GRANT_RUNTIME_PERMISSIONS"
+ android:theme="@style/Settings"/>
</application>
</manifest>
diff --git a/res/drawable-watch-280dpi/ic_cc_cancel.png b/res/drawable-watch-280dpi/ic_cc_cancel.png
new file mode 100644
index 00000000..249b8697
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_cc_cancel.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_cc_checkmark.png b/res/drawable-watch-280dpi/ic_cc_checkmark.png
new file mode 100644
index 00000000..94db9ab0
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_cc_checkmark.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_cc_deny.png b/res/drawable-watch-280dpi/ic_cc_deny.png
new file mode 100644
index 00000000..1733669f
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_cc_deny.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_calendar.png b/res/drawable-watch-280dpi/ic_permission_calendar.png
new file mode 100644
index 00000000..602bddf0
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_calendar.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_calendardisable.png b/res/drawable-watch-280dpi/ic_permission_calendardisable.png
new file mode 100644
index 00000000..b855932e
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_calendardisable.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_call.png b/res/drawable-watch-280dpi/ic_permission_call.png
new file mode 100644
index 00000000..bcf4f868
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_call.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_calldisable.png b/res/drawable-watch-280dpi/ic_permission_calldisable.png
new file mode 100644
index 00000000..4781e1fe
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_calldisable.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_camera.png b/res/drawable-watch-280dpi/ic_permission_camera.png
new file mode 100644
index 00000000..3d27269f
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_camera.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_cameradisable.png b/res/drawable-watch-280dpi/ic_permission_cameradisable.png
new file mode 100644
index 00000000..51fa2c38
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_cameradisable.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_contact.png b/res/drawable-watch-280dpi/ic_permission_contact.png
new file mode 100644
index 00000000..3e26bfbb
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_contact.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_contactdisable.png b/res/drawable-watch-280dpi/ic_permission_contactdisable.png
new file mode 100644
index 00000000..059b147c
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_contactdisable.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_location.png b/res/drawable-watch-280dpi/ic_permission_location.png
new file mode 100644
index 00000000..f002a9cf
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_location.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_locationdisable.png b/res/drawable-watch-280dpi/ic_permission_locationdisable.png
new file mode 100644
index 00000000..98bbb869
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_locationdisable.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_mic.png b/res/drawable-watch-280dpi/ic_permission_mic.png
new file mode 100644
index 00000000..1ed9c941
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_mic.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_micdisable.png b/res/drawable-watch-280dpi/ic_permission_micdisable.png
new file mode 100644
index 00000000..d74f59b9
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_micdisable.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_more.png b/res/drawable-watch-280dpi/ic_permission_more.png
new file mode 100644
index 00000000..f33e02bf
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_more.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_sensor.png b/res/drawable-watch-280dpi/ic_permission_sensor.png
new file mode 100644
index 00000000..712c5d40
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_sensor.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_sensordisable.png b/res/drawable-watch-280dpi/ic_permission_sensordisable.png
new file mode 100644
index 00000000..8faa436f
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_sensordisable.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_shield.png b/res/drawable-watch-280dpi/ic_permission_shield.png
new file mode 100644
index 00000000..78d6742b
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_shield.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_shielddisable.png b/res/drawable-watch-280dpi/ic_permission_shielddisable.png
new file mode 100644
index 00000000..f0ef4134
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_shielddisable.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_sms.png b/res/drawable-watch-280dpi/ic_permission_sms.png
new file mode 100644
index 00000000..39bb4b3e
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_sms.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_smsdisable.png b/res/drawable-watch-280dpi/ic_permission_smsdisable.png
new file mode 100644
index 00000000..e9375b1f
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_smsdisable.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_storage.png b/res/drawable-watch-280dpi/ic_permission_storage.png
new file mode 100644
index 00000000..60ec50c7
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_storage.png
Binary files differ
diff --git a/res/drawable-watch-280dpi/ic_permission_storagedisable.png b/res/drawable-watch-280dpi/ic_permission_storagedisable.png
new file mode 100644
index 00000000..987b8249
--- /dev/null
+++ b/res/drawable-watch-280dpi/ic_permission_storagedisable.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_cc_cancel.png b/res/drawable-watch-hdpi/ic_cc_cancel.png
new file mode 100644
index 00000000..a57893e1
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_cc_cancel.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_cc_checkmark.png b/res/drawable-watch-hdpi/ic_cc_checkmark.png
new file mode 100644
index 00000000..a18fe7ab
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_cc_checkmark.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_cc_deny.png b/res/drawable-watch-hdpi/ic_cc_deny.png
new file mode 100644
index 00000000..bab22a3d
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_cc_deny.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_calendar.png b/res/drawable-watch-hdpi/ic_permission_calendar.png
new file mode 100644
index 00000000..b7424699
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_calendar.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_calendardisable.png b/res/drawable-watch-hdpi/ic_permission_calendardisable.png
new file mode 100644
index 00000000..def76b03
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_calendardisable.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_call.png b/res/drawable-watch-hdpi/ic_permission_call.png
new file mode 100644
index 00000000..e14a6bd2
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_call.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_calldisable.png b/res/drawable-watch-hdpi/ic_permission_calldisable.png
new file mode 100644
index 00000000..e0f535ff
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_calldisable.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_camera.png b/res/drawable-watch-hdpi/ic_permission_camera.png
new file mode 100644
index 00000000..7c1df6ba
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_camera.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_cameradisable.png b/res/drawable-watch-hdpi/ic_permission_cameradisable.png
new file mode 100644
index 00000000..9637808a
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_cameradisable.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_contact.png b/res/drawable-watch-hdpi/ic_permission_contact.png
new file mode 100644
index 00000000..532e3a2c
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_contact.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_contactdisable.png b/res/drawable-watch-hdpi/ic_permission_contactdisable.png
new file mode 100644
index 00000000..32b45c53
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_contactdisable.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_location.png b/res/drawable-watch-hdpi/ic_permission_location.png
new file mode 100644
index 00000000..3d6c0b9d
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_location.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_locationdisable.png b/res/drawable-watch-hdpi/ic_permission_locationdisable.png
new file mode 100644
index 00000000..c2475e21
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_locationdisable.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_mic.png b/res/drawable-watch-hdpi/ic_permission_mic.png
new file mode 100644
index 00000000..8acb4c5f
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_mic.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_micdisable.png b/res/drawable-watch-hdpi/ic_permission_micdisable.png
new file mode 100644
index 00000000..a37a4e20
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_micdisable.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_more.png b/res/drawable-watch-hdpi/ic_permission_more.png
new file mode 100644
index 00000000..08808bc4
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_more.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_sensor.png b/res/drawable-watch-hdpi/ic_permission_sensor.png
new file mode 100644
index 00000000..fd2939ab
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_sensor.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_sensordisable.png b/res/drawable-watch-hdpi/ic_permission_sensordisable.png
new file mode 100644
index 00000000..487a4861
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_sensordisable.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_shield.png b/res/drawable-watch-hdpi/ic_permission_shield.png
new file mode 100644
index 00000000..cab08e47
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_shield.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_shielddisable.png b/res/drawable-watch-hdpi/ic_permission_shielddisable.png
new file mode 100644
index 00000000..548ac56c
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_shielddisable.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_sms.png b/res/drawable-watch-hdpi/ic_permission_sms.png
new file mode 100644
index 00000000..dc3db2f9
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_sms.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_smsdisable.png b/res/drawable-watch-hdpi/ic_permission_smsdisable.png
new file mode 100644
index 00000000..608c4d04
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_smsdisable.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_storage.png b/res/drawable-watch-hdpi/ic_permission_storage.png
new file mode 100644
index 00000000..031d989f
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_storage.png
Binary files differ
diff --git a/res/drawable-watch-hdpi/ic_permission_storagedisable.png b/res/drawable-watch-hdpi/ic_permission_storagedisable.png
new file mode 100644
index 00000000..08dc6625
--- /dev/null
+++ b/res/drawable-watch-hdpi/ic_permission_storagedisable.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_cc_cancel.png b/res/drawable-watch-mdpi/ic_cc_cancel.png
new file mode 100644
index 00000000..87fc65ab
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_cc_cancel.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_cc_checkmark.png b/res/drawable-watch-mdpi/ic_cc_checkmark.png
new file mode 100644
index 00000000..02c22b19
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_cc_checkmark.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_cc_deny.png b/res/drawable-watch-mdpi/ic_cc_deny.png
new file mode 100644
index 00000000..f3b29f7f
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_cc_deny.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_calendar.png b/res/drawable-watch-mdpi/ic_permission_calendar.png
new file mode 100644
index 00000000..6ae24429
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_calendar.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_calendardisable.png b/res/drawable-watch-mdpi/ic_permission_calendardisable.png
new file mode 100644
index 00000000..639109fa
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_calendardisable.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_call.png b/res/drawable-watch-mdpi/ic_permission_call.png
new file mode 100644
index 00000000..d67a03a5
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_call.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_calldisable.png b/res/drawable-watch-mdpi/ic_permission_calldisable.png
new file mode 100644
index 00000000..39760b74
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_calldisable.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_camera.png b/res/drawable-watch-mdpi/ic_permission_camera.png
new file mode 100644
index 00000000..807a66f6
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_camera.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_cameradisable.png b/res/drawable-watch-mdpi/ic_permission_cameradisable.png
new file mode 100644
index 00000000..edf4f7a7
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_cameradisable.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_contact.png b/res/drawable-watch-mdpi/ic_permission_contact.png
new file mode 100644
index 00000000..2e146e20
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_contact.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_contactdisable.png b/res/drawable-watch-mdpi/ic_permission_contactdisable.png
new file mode 100644
index 00000000..e3903516
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_contactdisable.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_location.png b/res/drawable-watch-mdpi/ic_permission_location.png
new file mode 100644
index 00000000..3862b24c
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_location.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_locationdisable.png b/res/drawable-watch-mdpi/ic_permission_locationdisable.png
new file mode 100644
index 00000000..1f875bd8
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_locationdisable.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_mic.png b/res/drawable-watch-mdpi/ic_permission_mic.png
new file mode 100644
index 00000000..33327f0d
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_mic.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_micdisable.png b/res/drawable-watch-mdpi/ic_permission_micdisable.png
new file mode 100644
index 00000000..7a1b39c4
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_micdisable.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_more.png b/res/drawable-watch-mdpi/ic_permission_more.png
new file mode 100644
index 00000000..a563f1a9
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_more.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_sensor.png b/res/drawable-watch-mdpi/ic_permission_sensor.png
new file mode 100644
index 00000000..59e1c01f
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_sensor.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_sensordisable.png b/res/drawable-watch-mdpi/ic_permission_sensordisable.png
new file mode 100644
index 00000000..d8d55c6d
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_sensordisable.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_shield.png b/res/drawable-watch-mdpi/ic_permission_shield.png
new file mode 100644
index 00000000..7773fa48
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_shield.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_shielddisable.png b/res/drawable-watch-mdpi/ic_permission_shielddisable.png
new file mode 100644
index 00000000..42f452bf
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_shielddisable.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_sms.png b/res/drawable-watch-mdpi/ic_permission_sms.png
new file mode 100644
index 00000000..11333ddb
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_sms.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_smsdisable.png b/res/drawable-watch-mdpi/ic_permission_smsdisable.png
new file mode 100644
index 00000000..b4416f4b
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_smsdisable.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_storage.png b/res/drawable-watch-mdpi/ic_permission_storage.png
new file mode 100644
index 00000000..07bd8f92
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_storage.png
Binary files differ
diff --git a/res/drawable-watch-mdpi/ic_permission_storagedisable.png b/res/drawable-watch-mdpi/ic_permission_storagedisable.png
new file mode 100644
index 00000000..ed8af410
--- /dev/null
+++ b/res/drawable-watch-mdpi/ic_permission_storagedisable.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_cc_cancel.png b/res/drawable-watch-xhdpi/ic_cc_cancel.png
new file mode 100644
index 00000000..fec6ecb8
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_cc_cancel.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_cc_checkmark.png b/res/drawable-watch-xhdpi/ic_cc_checkmark.png
new file mode 100644
index 00000000..1302723b
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_cc_checkmark.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_cc_deny.png b/res/drawable-watch-xhdpi/ic_cc_deny.png
new file mode 100644
index 00000000..a5f8dc1b
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_cc_deny.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_calendar.png b/res/drawable-watch-xhdpi/ic_permission_calendar.png
new file mode 100644
index 00000000..806438c6
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_calendar.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_calendardisable.png b/res/drawable-watch-xhdpi/ic_permission_calendardisable.png
new file mode 100644
index 00000000..821462e4
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_calendardisable.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_call.png b/res/drawable-watch-xhdpi/ic_permission_call.png
new file mode 100644
index 00000000..079942b5
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_call.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_calldisable.png b/res/drawable-watch-xhdpi/ic_permission_calldisable.png
new file mode 100644
index 00000000..13cd805e
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_calldisable.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_camera.png b/res/drawable-watch-xhdpi/ic_permission_camera.png
new file mode 100644
index 00000000..03b0d8d0
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_camera.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_cameradisable.png b/res/drawable-watch-xhdpi/ic_permission_cameradisable.png
new file mode 100644
index 00000000..bcb2a350
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_cameradisable.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_contact.png b/res/drawable-watch-xhdpi/ic_permission_contact.png
new file mode 100644
index 00000000..996fe39d
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_contact.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_contactdisable.png b/res/drawable-watch-xhdpi/ic_permission_contactdisable.png
new file mode 100644
index 00000000..1063f17b
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_contactdisable.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_location.png b/res/drawable-watch-xhdpi/ic_permission_location.png
new file mode 100644
index 00000000..d9dc1fc9
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_location.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_locationdisable.png b/res/drawable-watch-xhdpi/ic_permission_locationdisable.png
new file mode 100644
index 00000000..c3e7ae9f
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_locationdisable.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_mic.png b/res/drawable-watch-xhdpi/ic_permission_mic.png
new file mode 100644
index 00000000..3a951ea8
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_mic.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_micdisable.png b/res/drawable-watch-xhdpi/ic_permission_micdisable.png
new file mode 100644
index 00000000..a9c7c81e
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_micdisable.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_more.png b/res/drawable-watch-xhdpi/ic_permission_more.png
new file mode 100644
index 00000000..a3f7ee5b
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_more.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_sensor.png b/res/drawable-watch-xhdpi/ic_permission_sensor.png
new file mode 100644
index 00000000..73564014
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_sensor.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_sensordisable.png b/res/drawable-watch-xhdpi/ic_permission_sensordisable.png
new file mode 100644
index 00000000..ef135a7e
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_sensordisable.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_shield.png b/res/drawable-watch-xhdpi/ic_permission_shield.png
new file mode 100644
index 00000000..2fc8fd07
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_shield.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_shielddisable.png b/res/drawable-watch-xhdpi/ic_permission_shielddisable.png
new file mode 100644
index 00000000..08a862e8
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_shielddisable.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_sms.png b/res/drawable-watch-xhdpi/ic_permission_sms.png
new file mode 100644
index 00000000..c74ce084
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_sms.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_smsdisable.png b/res/drawable-watch-xhdpi/ic_permission_smsdisable.png
new file mode 100644
index 00000000..b7256772
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_smsdisable.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_storage.png b/res/drawable-watch-xhdpi/ic_permission_storage.png
new file mode 100644
index 00000000..1f16bdb6
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_storage.png
Binary files differ
diff --git a/res/drawable-watch-xhdpi/ic_permission_storagedisable.png b/res/drawable-watch-xhdpi/ic_permission_storagedisable.png
new file mode 100644
index 00000000..41d42d57
--- /dev/null
+++ b/res/drawable-watch-xhdpi/ic_permission_storagedisable.png
Binary files differ
diff --git a/res/drawable-watch/action_negative_bg.xml b/res/drawable-watch/action_negative_bg.xml
new file mode 100644
index 00000000..7b21ba6d
--- /dev/null
+++ b/res/drawable-watch/action_negative_bg.xml
@@ -0,0 +1,35 @@
+<?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");
+ 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false">
+ <shape android:shape="oval">
+ <solid android:color="@color/circular_button_disabled"/>
+ <size android:width="40dp" android:height="40dp" />
+ </shape>
+ </item>
+ <item android:state_pressed="true">
+ <shape android:shape="oval">
+ <solid android:color="#757575"/>
+ <size android:width="40dp" android:height="40dp" />
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="oval">
+ <solid android:color="#BDBDBD"/>
+ <size android:width="40dp" android:height="40dp" />
+ </shape>
+ </item>
+</selector>
diff --git a/res/drawable-watch/action_positive_bg.xml b/res/drawable-watch/action_positive_bg.xml
new file mode 100644
index 00000000..f3457c1a
--- /dev/null
+++ b/res/drawable-watch/action_positive_bg.xml
@@ -0,0 +1,35 @@
+<?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");
+ 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false">
+ <shape android:shape="oval">
+ <solid android:color="@color/circular_button_disabled"/>
+ <size android:width="40dp" android:height="40dp" />
+ </shape>
+ </item>
+ <item android:state_pressed="true">
+ <shape android:shape="oval">
+ <solid android:color="#009688"/>
+ <size android:width="40dp" android:height="40dp" />
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="oval">
+ <solid android:color="#00BFA5"/>
+ <size android:width="40dp" android:height="40dp" />
+ </shape>
+ </item>
+</selector>
diff --git a/res/drawable-watch/cancel_button.xml b/res/drawable-watch/cancel_button.xml
new file mode 100644
index 00000000..641526a5
--- /dev/null
+++ b/res/drawable-watch/cancel_button.xml
@@ -0,0 +1,21 @@
+<?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");
+ 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:drawable="@drawable/action_negative_bg" />
+ <item>
+ <bitmap android:src="@drawable/ic_cc_cancel" android:gravity="center" />
+ </item>
+</layer-list>
diff --git a/res/drawable-watch/confirm_button.xml b/res/drawable-watch/confirm_button.xml
new file mode 100644
index 00000000..2b53e42e
--- /dev/null
+++ b/res/drawable-watch/confirm_button.xml
@@ -0,0 +1,21 @@
+<?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");
+ 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:drawable="@drawable/action_positive_bg" />
+ <item>
+ <bitmap android:src="@drawable/ic_cc_checkmark" android:gravity="center" />
+ </item>
+</layer-list>
diff --git a/res/drawable-watch/deny_button.xml b/res/drawable-watch/deny_button.xml
new file mode 100644
index 00000000..1e7582bc
--- /dev/null
+++ b/res/drawable-watch/deny_button.xml
@@ -0,0 +1,21 @@
+<?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");
+ 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:drawable="@drawable/action_negative_bg" />
+ <item>
+ <bitmap android:src="@drawable/ic_cc_deny" android:gravity="center" />
+ </item>
+</layer-list>
diff --git a/res/layout-watch/confirmation_dialog.xml b/res/layout-watch/confirmation_dialog.xml
new file mode 100644
index 00000000..ea25b6b4
--- /dev/null
+++ b/res/layout-watch/confirmation_dialog.xml
@@ -0,0 +1,131 @@
+<?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");
+ 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:id="@+id/confirmation"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ScrollView
+ android:id="@+id/scrolling_container"
+ android:overScrollMode="never"
+ android:scrollbars="none"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@+id/content"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/conf_diag_content_padding_top">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/conf_diag_min_space_above_message"
+ android:gravity="bottom">
+ <TextView
+ android:id="@+id/current_page_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="@dimen/grant_permissions_app_breadcrumb_margin_top"
+ android:textAppearance="@style/GrantPermissions.BreadcrumbText" />
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/grant_permissions_app_icon_size"
+ android:layout_height="@dimen/grant_permissions_app_icon_size"
+ android:tint="@color/grant_permissions_app_color"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="@dimen/grant_permissions_app_icon_margin_top"/>
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/grant_permissions_title_margin_top"
+ android:paddingLeft="@dimen/grant_permissions_message_side_padding"
+ android:paddingRight="@dimen/grant_permissions_message_side_padding"
+ android:gravity="center"
+ android:textAppearance="@style/GrantPermissions.TitleText"/>
+ </LinearLayout>
+ </ScrollView>
+
+ <!-- TODO: Change this to use a ViewStub instead of show/hiding the two layouts -->
+ <FrameLayout android:id="@+id/button_bar_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:background="#FF606060">
+ <FrameLayout
+ android:id="@+id/horizontal_button_bar"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/conf_diag_button_container_height">
+ <Button
+ android:id="@+id/permission_deny_button"
+ android:layout_width="54dp"
+ android:layout_height="54dp"
+ android:layout_gravity="top|left"
+ android:layout_marginLeft="@dimen/conf_diag_2button_margin_side"
+ android:layout_marginTop="@dimen/conf_diag_2button_margin_top"
+ android:background="@drawable/cancel_button"/>
+
+ <Button
+ android:id="@+id/permission_allow_button"
+ android:layout_width="54dp"
+ android:layout_height="54dp"
+ android:layout_gravity="top|right"
+ android:layout_marginRight="@dimen/conf_diag_2button_margin_side"
+ android:layout_marginTop="@dimen/conf_diag_2button_margin_top"
+ android:background="@drawable/confirm_button"/>
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/vertical_button_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/conf_diag_3button_padding_side"
+ android:paddingRight="@dimen/conf_diag_3button_padding_side"
+ android:visibility="gone">
+ <LinearLayout
+ android:id="@+id/buttonPanel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <Button
+ android:id="@+id/vertical_button1"
+ style="@style/Widget.WearDiag.Button"/>
+
+ <Button
+ android:id="@+id/vertical_button2"
+ style="@style/Widget.WearDiag.Button"/>
+
+ <Button
+ android:id="@+id/vertical_button3"
+ style="@style/Widget.WearDiag.Button"/>
+
+ <!-- Adding padding to the bottom button causes rendering issues, so add
+ an empty view here instead -->
+ <Space android:layout_width="match_parent"
+ android:layout_height="@dimen/conf_diag_3button_padding_bottom"/>
+ </LinearLayout>
+ </FrameLayout>
+ </FrameLayout>
+</FrameLayout>
diff --git a/res/layout-watch/permissions_settings_item.xml b/res/layout-watch/permissions_settings_item.xml
new file mode 100644
index 00000000..b370f1ac
--- /dev/null
+++ b/res/layout-watch/permissions_settings_item.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+ <android.support.wearable.view.CircledImageView
+ android:id="@+id/image"
+ android:alpha="0.5"
+ android:layout_height="52dp"
+ android:layout_width="52dp"
+ android:layout_gravity="center_vertical"
+ app:circle_border_color="#FFFFFFFF"
+ app:circle_border_width="1dp"
+ app:circle_color="#00000000"
+ app:image_tint="#FFFFFFFF"/>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/settings_text_margin_left"
+ android:layout_gravity="center_vertical"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/text"
+ android:alpha="0.5"
+ android:fontFamily="sans-serif-condensed-light"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/permissions_settings_item_color"
+ android:textSize="14sp"
+ android:maxLines="2"
+ android:ellipsize="end"/>
+ <TextView
+ android:id="@+id/state"
+ android:alpha="0.5"
+ android:fontFamily="sans-serif-condensed-light"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/permissions_settings_item_color"
+ android:textSize="14sp"
+ android:maxLines="1"
+ android:ellipsize="end"/>
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout-watch/settings.xml b/res/layout-watch/settings.xml
new file mode 100644
index 00000000..46249d50
--- /dev/null
+++ b/res/layout-watch/settings.xml
@@ -0,0 +1,21 @@
+<?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");
+ 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:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <include layout="@layout/settings_internal" />
+</FrameLayout>
diff --git a/res/layout-watch/settings_internal.xml b/res/layout-watch/settings_internal.xml
new file mode 100644
index 00000000..fdd21cef
--- /dev/null
+++ b/res/layout-watch/settings_internal.xml
@@ -0,0 +1,37 @@
+<?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");
+ 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <TextView
+ android:id="@+id/header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/settings_header_base_height"
+ android:layout_marginLeft="16dp"
+ android:layout_marginTop="@dimen/settings_header_top_margin"
+ android:textSize="@dimen/setting_short_header_text_size"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:textColor="#9E9E9E"
+ android:fontFamily="sans-serif-condensed-light"
+ />
+
+ <android.support.wearable.view.WearableListView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/wheel"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ />
+</merge>
diff --git a/res/values-af-watch/strings.xml b/res/values-af-watch/strings.xml
new file mode 100644
index 00000000..c32ca2b1
--- /dev/null
+++ b/res/values-af-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Weier; moenie weer vra nie"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Wys stelselprogramme"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Onveranderbaar"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"GEAKTIVEER"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"GEDEAKTIVEER"</string>
+</resources>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 0588dacb..635c28b3 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Skermoorlegger bespeur"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Om hierdie toestemminginstelling te verander, moet jy eers die skermoorlegger by Instellings &gt; Programme afskakel"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Maak instellings oop"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Installeer- en deïnstalleerhandelinge word nie in Wear gesteun nie."</string>
</resources>
diff --git a/res/values-am-watch/strings.xml b/res/values-am-watch/strings.xml
new file mode 100644
index 00000000..73397e34
--- /dev/null
+++ b/res/values-am-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"ከልክል፣ ዳግም አትጠይቅ"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"የስርዓት መተግበሪያዎችን አሳይ"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"ሊለወጥ አይችልም"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ነቅቷል"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ተሰናክሏል"</string>
+</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 942e3a1d..0b0396fa 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"የማያ ገጽ ተደራቢ ተገኝቷል"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"ይህን የፍቃድ ቅንብር ለመቀየር መጀመሪያ የማያ ገጽ ተደራቢውን ከቅንብሮች &gt; መተግበሪያዎች ማጥፋት አለብዎ"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"ቅንብሮችን ክፈት"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"በWear ላይ የመጫን/ማራገፍ እርምጃዎች አይደገፉም።"</string>
</resources>
diff --git a/res/values-ar-watch/strings.xml b/res/values-ar-watch/strings.xml
new file mode 100644
index 00000000..144f7868
--- /dev/null
+++ b/res/values-ar-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"الرفض وعدم السؤال مرة أخرى"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"عرض تطبيقات النظام"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"لا يمكن التغيير"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ممكّن"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"معطّل"</string>
+</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index a4e761a7..788cd44b 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -122,4 +122,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"تم اكتشاف طبقة متراكبة للشاشة"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"لتغيير إعداد هذا الإذن، يتعين عليك أولاً تعطيل الطبقة المتراكبة للشاشة من الإعدادات &gt; التطبيقات"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"فتح الإعدادات"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"‏لا تتوافق إجراءات التثبيت/إلغاء التثبيت مع Wear."</string>
</resources>
diff --git a/res/values-az-rAZ-watch/strings.xml b/res/values-az-rAZ-watch/strings.xml
new file mode 100644
index 00000000..5d28398e
--- /dev/null
+++ b/res/values-az-rAZ-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Rədd edin, bir daha soruşmayın"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Sistem tətbiqlərini göstərin"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Dəyişdirilə bilməz"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"AKTİV"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DEAKTİV"</string>
+</resources>
diff --git a/res/values-az-rAZ/strings.xml b/res/values-az-rAZ/strings.xml
index 5fb8257b..d1c9e238 100644
--- a/res/values-az-rAZ/strings.xml
+++ b/res/values-az-rAZ/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Ekran örtüyü aşkarlandı"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Bu icazə ayarını dəyişdirmək üçün əvvəldə Ayarlar və Tətbiqlər bölməsindən ekran örtüyünü söndürməlisiniz"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Ayarları açın"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Yükləmə/Silmə fəaliyyətləri Wear\'də dəstəklənmir."</string>
</resources>
diff --git a/res/values-bg-watch/strings.xml b/res/values-bg-watch/strings.xml
new file mode 100644
index 00000000..af81f2a8
--- /dev/null
+++ b/res/values-bg-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Отказ, без повторно запитване"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Показване на системните приложения"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Без промяна"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"АКТИВИРАНО"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ДЕАКТИВИРАНО"</string>
+</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 4260da34..74d29a98 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Открито е екранно наслагване"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"За да промените настройката за това разрешение, трябва първо да изключите екранното наслагване от „Настройки“ &gt; „Приложения“"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Отваряне на настройките"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Действията инсталиране и деинсталиране не се поддържат на устройства с Wear."</string>
</resources>
diff --git a/res/values-bn-rBD-watch/strings.xml b/res/values-bn-rBD-watch/strings.xml
new file mode 100644
index 00000000..d642be1c
--- /dev/null
+++ b/res/values-bn-rBD-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"অস্বীকার করুন, আবার জিজ্ঞাসা করবেন না"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"সিস্টেম অ্যাপ্লিকেশানগুলি দেখান"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"পরিবর্তন করা যাবে না"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"সক্ষম করা রয়েছে"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"অক্ষম করা রয়েছে"</string>
+</resources>
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml
index 59bef73a..ce13ce54 100644
--- a/res/values-bn-rBD/strings.xml
+++ b/res/values-bn-rBD/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"স্ক্রীন আচ্ছাদন সনাক্ত করা হয়েছে"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"এই অনুমতি সেটিংস পরিবর্তন করতে, আপনাকে প্রথমে সেটিংস &gt; এ গিয়ে অ্যাপ্লিকেশানগুলি থেকে স্ক্রীন ওভারলে বন্ধ করতে হবে"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"সেটিংস খুলুন"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wearএ ইনস্টল/আনইনস্টল করার ক্রিয়াগুলি সমর্থিত নয়।"</string>
</resources>
diff --git a/res/values-ca-watch/strings.xml b/res/values-ca-watch/strings.xml
new file mode 100644
index 00000000..c4f9e3ff
--- /dev/null
+++ b/res/values-ca-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Denega i no m\'ho demanis més"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Mostra les aplicacions del sistema"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"No es pot canviar"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ACTIVAT"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DESACTIVAT"</string>
+</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index c9ce7952..e6971748 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"S\'ha detectat una superposició de pantalla"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Per canviar la configuració de permisos, cal que desactivis la superposició de pantalla des de Configuració &gt; Aplicacions"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Obre Configuració"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Les accions d\'instal·lar o desinstal·lar no s\'admeten a Wear."</string>
</resources>
diff --git a/res/values-cs-watch/strings.xml b/res/values-cs-watch/strings.xml
new file mode 100644
index 00000000..ae6cfbcf
--- /dev/null
+++ b/res/values-cs-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Odmítnout a již se neptat"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Zobrazit systémové aplikace"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Nelze změnit"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ZAPNUTO"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"VYPNUTO"</string>
+</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 84db63a6..ecc9ce20 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -120,4 +120,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Byla zjištěna překryvná vrstva obrazovky"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Chcete-li změnit nastavení tohoto oprávnění, v Nastavení &gt; Aplikace je třeba nejprve vypnout překryvnou vrstvu obrazovky"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Otevřít nastavení"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Akce instalace/odinstalace nejsou v zařízení Wear podporovány."</string>
</resources>
diff --git a/res/values-da-watch/strings.xml b/res/values-da-watch/strings.xml
new file mode 100644
index 00000000..2fd6279d
--- /dev/null
+++ b/res/values-da-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Afvis, og spørg ikke igen"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Vis systemapps"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Kan ikke ændres"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"AKTIVERET"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DEAKTIVERET"</string>
+</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index c7575642..b88dc3b6 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Der er registreret skærmoverlejring"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Hvis du vil ændre denne indstilling for tilladelser, skal du først slå skærmoverlejringen fra i Indstillinger &gt; Apps"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Åbn indstillingerne"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Det er ikke muligt at installere/afinstallere på Wear."</string>
</resources>
diff --git a/res/values-de-watch/strings.xml b/res/values-de-watch/strings.xml
new file mode 100644
index 00000000..be893682
--- /dev/null
+++ b/res/values-de-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Ablehnen &amp; nicht mehr fragen"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"System-Apps anzeigen"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Keine Änderung möglich"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"Aktiviert"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"Deaktiviert"</string>
+</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index de59d6e5..0208d4a2 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Display-Overlay erkannt"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Um diese Berechtigungseinstellung zu ändern, musst du zunächst das Display-Overlay über \"Einstellungen\" &gt; \"Apps\" deaktivieren."</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Einstellungen öffnen"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Von Android Wear nicht unterstützte Aktionen installieren/deinstallieren."</string>
</resources>
diff --git a/res/values-el-watch/strings.xml b/res/values-el-watch/strings.xml
new file mode 100644
index 00000000..2aa34551
--- /dev/null
+++ b/res/values-el-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Απόρριψη και να μην ερωτηθώ ξανά"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Εμφάνιση εφαρμογών συστήματος"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Δεν είναι δυνατή η αλλαγή"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ΕΝΕΡΓΟ"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ΑΝΕΝΕΡΓΟ"</string>
+</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index c549a166..a4094cd5 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Εντοπίστηκε επικάλυψη οθόνης"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Για να αλλάξετε αυτή τη ρύθμιση άδειας, θα πρέπει πρώτα να απενεργοποιήσετε την επικάλυψη οθόνης από τις Ρυθμίσεις &gt; Εφαρμογές"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Άνοιγμα ρυθμίσεων"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Οι ενέργειες εγκατάστασης/απεγκατάστασης δεν υποστηρίζονται στο Wear."</string>
</resources>
diff --git a/res/values-en-rAU-watch/strings.xml b/res/values-en-rAU-watch/strings.xml
new file mode 100644
index 00000000..755d64f0
--- /dev/null
+++ b/res/values-en-rAU-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Deny, don\'t ask again"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Show system apps"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Can\'t be changed"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ENABLED"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DISABLED"</string>
+</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 3986d336..939ce47a 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Screen overlay detected"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"To change this permission setting, you first have to turn off the screen overlay from Settings &gt; Apps"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Open settings"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Install/Uninstall actions not supported on Wear."</string>
</resources>
diff --git a/res/values-en-rGB-watch/strings.xml b/res/values-en-rGB-watch/strings.xml
new file mode 100644
index 00000000..755d64f0
--- /dev/null
+++ b/res/values-en-rGB-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Deny, don\'t ask again"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Show system apps"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Can\'t be changed"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ENABLED"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DISABLED"</string>
+</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 3986d336..939ce47a 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Screen overlay detected"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"To change this permission setting, you first have to turn off the screen overlay from Settings &gt; Apps"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Open settings"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Install/Uninstall actions not supported on Wear."</string>
</resources>
diff --git a/res/values-en-rIN-watch/strings.xml b/res/values-en-rIN-watch/strings.xml
new file mode 100644
index 00000000..755d64f0
--- /dev/null
+++ b/res/values-en-rIN-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Deny, don\'t ask again"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Show system apps"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Can\'t be changed"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ENABLED"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DISABLED"</string>
+</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 3986d336..939ce47a 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Screen overlay detected"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"To change this permission setting, you first have to turn off the screen overlay from Settings &gt; Apps"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Open settings"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Install/Uninstall actions not supported on Wear."</string>
</resources>
diff --git a/res/values-es-rUS-watch/strings.xml b/res/values-es-rUS-watch/strings.xml
new file mode 100644
index 00000000..120b19bd
--- /dev/null
+++ b/res/values-es-rUS-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Denegar y no preguntar más"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Mostrar aplicaciones del sistema"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Inalterable"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"HABILITADA"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"INHABILITADA"</string>
+</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index d65fa542..2c3165ae 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Se detectó una superposición de pantalla"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Para cambiar esta configuración de permisos, primero debes desactivar la superposición de pantalla en Configuración &gt; Aplicaciones"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Abrir configuración"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"No se admiten las acciones de instalación y desinstalación en Wear."</string>
</resources>
diff --git a/res/values-es-watch/strings.xml b/res/values-es-watch/strings.xml
new file mode 100644
index 00000000..6d0c8af8
--- /dev/null
+++ b/res/values-es-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Denegar y no preguntar más"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Mostrar aplicaciones del sistema"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"No se puede cambiar"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"HABILITADO"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"INHABILITADA"</string>
+</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 04270e4b..d5e3059b 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Superposición de pantalla detectada"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Para cambiar la configuración de este permiso, desactiva la superposición de pantalla en Ajustes &gt; Aplicaciones"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Abrir ajustes"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"No puedes instalar ni desinstalar aplicaciones en Wear."</string>
</resources>
diff --git a/res/values-et-rEE-watch/strings.xml b/res/values-et-rEE-watch/strings.xml
new file mode 100644
index 00000000..947809d9
--- /dev/null
+++ b/res/values-et-rEE-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Keela, ära enam küsi"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Kuva süsteemirakendused"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Ei saa muuta"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"LUBATUD"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"KEELATUD"</string>
+</resources>
diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml
index 9f17942b..e600f68a 100644
--- a/res/values-et-rEE/strings.xml
+++ b/res/values-et-rEE/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Tuvastati ekraani ülekate"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Selle loa seade muutmiseks peate esmalt välja lülitama ekraani ülekatte menüüs Seaded &gt; Rakendused"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Ava seaded"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear ei toeta installimist/desinstallimist."</string>
</resources>
diff --git a/res/values-eu-rES-watch/strings.xml b/res/values-eu-rES-watch/strings.xml
new file mode 100644
index 00000000..25e2429e
--- /dev/null
+++ b/res/values-eu-rES-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Ukatu; ez galdetu berriro"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Erakutsi sistema-aplikazioak"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Ezin da aldatu"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"GAITUTA"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DESGAITUTA"</string>
+</resources>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
index 706e1888..d358c1fd 100644
--- a/res/values-eu-rES/strings.xml
+++ b/res/values-eu-rES/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Pantailaren gainjartzea detektatu da"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Baimen-ezarpen hau aldatzeko, pantailaren gainjartzea desaktibatu behar duzu Ezarpenak &gt; Aplikazioak atalean"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Ireki ezarpenak"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Instalatzeko eta desinstalatzeko ekintzak ezin dira gauzatu Wear gailuetan."</string>
</resources>
diff --git a/res/values-fa-watch/strings.xml b/res/values-fa-watch/strings.xml
new file mode 100644
index 00000000..15029959
--- /dev/null
+++ b/res/values-fa-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"رد شود، دیگر سؤال نشود"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"نمایش‌ برنامه‌های سیستم"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"نمی‌تواند تغییر کند"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"فعال شد"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"غیرفعال شد"</string>
+</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 54c6396b..09e20092 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"هم‌پوشانی صفحه شناسایی شد"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"‏برای تغییر این تنظیم مجوز، ابتدا باید هم‌پوشانی صفحه را از «تنظیمات &gt; برنامه‌ها» خاموش کنید"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"باز کردن تنظیمات"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"‏نصب/حذف نصب عملکردها در Wear پشتیبانی نمی‌شود."</string>
</resources>
diff --git a/res/values-fi-watch/strings.xml b/res/values-fi-watch/strings.xml
new file mode 100644
index 00000000..5305299c
--- /dev/null
+++ b/res/values-fi-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Hylkää, äläkä kysy uudelleen"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Näytä järjestelmäsovellukset"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Ei muutettavissa"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"KÄYTÖSSÄ"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"POIS KÄYTÖSTÄ"</string>
+</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 4c69ed96..e7999d36 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Näytön peittokuva havaittiin"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Ennen kuin voit muokata tätä käyttöoikeusasetusta, sinun täytyy poistaa näytön peittokuva käytöstä Asetukset-valikon Sovellukset-kohdasta."</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Avaa Asetukset"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear ei tue asennus- ja poistotoimintoja."</string>
</resources>
diff --git a/res/values-fr-rCA-watch/strings.xml b/res/values-fr-rCA-watch/strings.xml
new file mode 100644
index 00000000..cb176c27
--- /dev/null
+++ b/res/values-fr-rCA-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Refuser et ne plus demander"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Afficher les applications système"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Inchangeable"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ACTIVÉ"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DÉSACTIVÉ"</string>
+</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index e51f39d6..27c509bb 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"La superposition d\'écran a été détectée"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Pour modifier ce paramètre d\'autorisation, vous devez tout d\'abord désactiver la superposition d\'écran en accédant à Paramètres &gt; Applications."</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Ouvrir les paramètres"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Les actions d\'installation et de désinstallation ne sont pas prises en charge par Android Wear."</string>
</resources>
diff --git a/res/values-fr-watch/strings.xml b/res/values-fr-watch/strings.xml
new file mode 100644
index 00000000..c567d03b
--- /dev/null
+++ b/res/values-fr-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Refuser et ne plus demander"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Afficher les applications système"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Non modifiable"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ACTIVÉ"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DÉSACTIVÉ"</string>
+</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index bd1f9440..a7ff6998 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Superposition d\'écran détectée"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Pour modifier ce paramètre d\'autorisation, vous devez tout d\'abord désactiver la superposition d\'écran en accédant à Paramètres &gt; Applications."</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Ouvrir les paramètres"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Opérations d\'installation et de désinstallation impossibles sur Android Wear"</string>
</resources>
diff --git a/res/values-gl-rES-watch/strings.xml b/res/values-gl-rES-watch/strings.xml
new file mode 100644
index 00000000..38e4e6cb
--- /dev/null
+++ b/res/values-gl-rES-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Denegar, non volver preguntar"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Mostrar aplicacións do sistema"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Cambio imposible"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ACTIVADO"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DESACTIVADO"</string>
+</resources>
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml
index 19245166..477169ea 100644
--- a/res/values-gl-rES/strings.xml
+++ b/res/values-gl-rES/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Detectouse a superposición da pantalla"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Para cambiar a configuración deste permiso, primeiro tes que desactivar a superposición da pantalla en Configuración &gt; Aplicacións"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Abrir configuración"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"As accións de instalar e desinstalar non son compatibles con Wear."</string>
</resources>
diff --git a/res/values-gu-rIN-watch/strings.xml b/res/values-gu-rIN-watch/strings.xml
new file mode 100644
index 00000000..3530b6a9
--- /dev/null
+++ b/res/values-gu-rIN-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"નકારો, ફરીથી પૂછશો નહીં"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"સિસ્ટમ એપ્લિકેશનો બતાવો"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"બદલી શકતાં નથી"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"સક્ષમ કરેલ"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"અક્ષમ કરેલ"</string>
+</resources>
diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu-rIN/strings.xml
index fb11e93f..40951dd2 100644
--- a/res/values-gu-rIN/strings.xml
+++ b/res/values-gu-rIN/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"સ્ક્રીન ઓવરલે મળ્યું"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"આ પરવાનગી સેટિંગ બદલવા માટે, તમારે પહેલા સેટિંગ્સ &gt; Apps માંથી સ્ક્રીન ઓવરલે બંધ કરવું પડશે"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"સેટિંગ્સ ખોલો"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear પર ઇન્સ્ટૉલ/અનઇન્સ્ટૉલ ક્રિયાઓ સમર્થિત નથી."</string>
</resources>
diff --git a/res/values-hi-watch/strings.xml b/res/values-hi-watch/strings.xml
new file mode 100644
index 00000000..39c93948
--- /dev/null
+++ b/res/values-hi-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"मना करें, फिर से ना पूछें"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"सिस्टम ऐप्स दिखाएं"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"बदला नहीं जा सकता"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"सक्षम"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"अक्षम"</string>
+</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 0ca0ab17..0f353d30 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"स्क्रीन ओवरले को पहचाना गया"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"इस अनुमति सेटिंग को बदलने के लिए, आपको पहले सेटिंग &gt; ऐप्स से स्क्रीन ओवरले को बंद करना होगा"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"सेटिंग खोलें"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"इंस्टॉल/अनइंस्टॉल किए जाने की कार्रवाइयां Wear पर समर्थित नहीं हैं."</string>
</resources>
diff --git a/res/values-hr-watch/strings.xml b/res/values-hr-watch/strings.xml
new file mode 100644
index 00000000..37658e5e
--- /dev/null
+++ b/res/values-hr-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Ne, više ne pitaj"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Prikaži aplikacije sustava"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Promjena nemoguća"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"OMOGUĆENO"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ONEMOGUĆENO"</string>
+</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index be51e443..8cead087 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -119,4 +119,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Otkriveno je preklapanje na zaslonu"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Da biste promijenili tu postavku dopuštenja, prvo morate isključiti preklapanje na zaslonu u Postavkama &gt; Aplikacije"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Otvori postavke"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Radnje instaliranja i deinstaliranja nisu podržane na Wearu."</string>
</resources>
diff --git a/res/values-hu-watch/strings.xml b/res/values-hu-watch/strings.xml
new file mode 100644
index 00000000..8a116dff
--- /dev/null
+++ b/res/values-hu-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Megtagadás, ne jelenjen meg"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>/<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Rendszeralkalmazások megjelenítése"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Nem változtatható"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ENGEDÉLYEZVE"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"LETILTVA"</string>
+</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 9c8b1db2..84aab320 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Képernyőfedvény észlelve"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Ennek az engedélynek a módosításához először ki kell kapcsolnia a képernyőfedvényt a Beállítások &gt; Alkalmazások menüben"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Beállítások megnyitása"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"A Wear nem támogatja a telepítés/eltávolítás műveletet."</string>
</resources>
diff --git a/res/values-hy-rAM-watch/strings.xml b/res/values-hy-rAM-watch/strings.xml
new file mode 100644
index 00000000..08786c11
--- /dev/null
+++ b/res/values-hy-rAM-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Մերժել, այլևս չհարցնել"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Ցուցադրել համակարգի հավելվածները"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Հնարավոր չէ փոխել"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ՄԻԱՑՎԱԾ"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ԱՆՋԱՏՎԱԾ"</string>
+</resources>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
index b4b4fde3..00a4e301 100644
--- a/res/values-hy-rAM/strings.xml
+++ b/res/values-hy-rAM/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Հայտնաբերվել է էկրանի վերադրում"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Այս թույլտվության կարգավորումները փոխելու համար նախ անհրաժեշտ է անջատել էկրանի վերադրումը՝ անցնելով Կարգավորումներ &gt; Հավելվածներ"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Բացել կարգավորումները"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Տեղադրման/հեռացման գործողությունները Android Wear-ում չեն աջակցվում:"</string>
</resources>
diff --git a/res/values-in-watch/strings.xml b/res/values-in-watch/strings.xml
new file mode 100644
index 00000000..38ad48b9
--- /dev/null
+++ b/res/values-in-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Tolak, jangan tanya lagi"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Tampilkan aplikasi sistem"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Tidak dapat diubah"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"DIAKTIFKAN"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DINONAKTIFKAN"</string>
+</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 589f2954..c20e0b6e 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Hamparan layar terdeteksi"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Untuk mengubah setelan izin ini, terlebih dahulu Anda harus menonaktifkan hamparan layar dari Setelan &gt; Aplikasi"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Buka setelan"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Tindakan Pasang/Copot Pemasangan tidak didukung di Wear."</string>
</resources>
diff --git a/res/values-is-rIS-watch/strings.xml b/res/values-is-rIS-watch/strings.xml
new file mode 100644
index 00000000..c8f92448
--- /dev/null
+++ b/res/values-is-rIS-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Hafna, ekki spyrja aftur"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Sýna kerfisforrit"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Má ekki breyta"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"VIRKT"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ÓVIRKT"</string>
+</resources>
diff --git a/res/values-is-rIS/strings.xml b/res/values-is-rIS/strings.xml
index 41d176df..7a5a39c9 100644
--- a/res/values-is-rIS/strings.xml
+++ b/res/values-is-rIS/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Skjáyfirlögn greindist"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Til að breyta þessari heimildarstillingu þarftu fyrst að slökkva á skjáyfirlögn undir Stillingar &gt; Forrit"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Opna stillingar"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Uppsetningar-/fjarlægingaraðgerðir eru ekki studdar í Wear."</string>
</resources>
diff --git a/res/values-it-watch/strings.xml b/res/values-it-watch/strings.xml
new file mode 100644
index 00000000..4a44dca9
--- /dev/null
+++ b/res/values-it-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Nega e non chiedermelo più"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Mostra app di sistema"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Imposs modif"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ATTIVATO"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DISATTIVATO"</string>
+</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 68543309..442d78ca 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Overlay schermo rilevato"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Per modificare questa impostazione di autorizzazione, devi innanzitutto disattivare l\'overlay schermo da Impostazioni &gt; App"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Apri impostazioni"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Le azioni di installazione/disinstallazione non sono supportate su Wear."</string>
</resources>
diff --git a/res/values-iw-watch/strings.xml b/res/values-iw-watch/strings.xml
new file mode 100644
index 00000000..d27e2d7d
--- /dev/null
+++ b/res/values-iw-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"דחה ואל תשאל שוב"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"הצג אפליקציות מערכת"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"לא ניתן לשנות"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"מופעל"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"מושבת"</string>
+</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index e2f1057b..fc22c872 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -120,4 +120,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"זוהתה שכבת על במסך"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"‏כדי לשנות את הגדרת ההרשאה הזו, ראשית עליך לכבות את שכבת העל במסך ב\'הגדרות\' &gt; \'אפליקציות\'"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"פתח הגדרות"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"‏פעולות התקנה/הסרת התקנה אינן נתמכות ב-Wear."</string>
</resources>
diff --git a/res/values-ja-watch/strings.xml b/res/values-ja-watch/strings.xml
new file mode 100644
index 00000000..f3e83c84
--- /dev/null
+++ b/res/values-ja-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"許可しない(今後表示しない)"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"システムアプリの表示"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"変更不可"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"有効"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"無効"</string>
+</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index f5f294e9..dc32fc37 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"画面オーバーレイを検出"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"この権限設定を変更するには、まず[設定]&gt;[アプリ]から画面オーバーレイをOFFにします"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"設定を開く"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wearでのインストールおよびアンインストール操作はサポートされていません。"</string>
</resources>
diff --git a/res/values-ka-rGE-watch/strings.xml b/res/values-ka-rGE-watch/strings.xml
new file mode 100644
index 00000000..6498a4dc
--- /dev/null
+++ b/res/values-ka-rGE-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"უარყავი და აღარ მკითხო"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"სისტემის აპების ჩვენება"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"ვერ შეიცვლება"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ჩართულია"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"გამორთულია"</string>
+</resources>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
index 41ce43b3..f365a6cf 100644
--- a/res/values-ka-rGE/strings.xml
+++ b/res/values-ka-rGE/strings.xml
@@ -119,4 +119,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"ეკრანის გადაფარვა გამოვლინდა"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"ამ ნებართვის პარამეტრის შესაცვლელად, ჯერ უნდა გამორთოთ ეკრანის გადაფარვა პარამეტრებიდან &gt; აპებიდან"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"პარამეტრების გახსნა"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"ინსტალაციის/დეინსტალაციის მოქმედებები არ არის მხარდაჭერილი Wear-ზე."</string>
</resources>
diff --git a/res/values-kk-rKZ-watch/strings.xml b/res/values-kk-rKZ-watch/strings.xml
new file mode 100644
index 00000000..dfff10bf
--- /dev/null
+++ b/res/values-kk-rKZ-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Тыйым салу, қайтадан сұрамау"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Жүйелік қолданбаларды көрсету"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Өзгерту мүмкін емес"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ҚОСЫЛҒАН"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ӨШІРІЛГЕН"</string>
+</resources>
diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml
index 8fe10ee4..c450d48b 100644
--- a/res/values-kk-rKZ/strings.xml
+++ b/res/values-kk-rKZ/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Экранды қабаттастыру анықталды"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Бұл рұқсат параметрін өзгерту үшін алдымен «Параметрлер» &gt; «Қолданбалар» тармағында экранды қабаттастыруды өшіру керек"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Параметрлерді ашу"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear құрылғысында \"Орнату\"/\"Жою\" әрекеттеріне қолдау көрсетілмейді."</string>
</resources>
diff --git a/res/values-km-rKH-watch/strings.xml b/res/values-km-rKH-watch/strings.xml
new file mode 100644
index 00000000..1beebfdb
--- /dev/null
+++ b/res/values-km-rKH-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"បដិសេធ សូមកុំសួរម្តងទៀត"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"បង្ហាញកម្មវិធីប្រព័ន្ធ"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"មិនអាចប្តូរបានទេ"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"បានបើកដំណើរការ"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"បានបិទដំណើរការ"</string>
+</resources>
diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml
index 6396a99e..f8958c0a 100644
--- a/res/values-km-rKH/strings.xml
+++ b/res/values-km-rKH/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"បានរកឃើញអេក្រង់ត្រួតគ្នា"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"ដើម្បីប្តូរការកំណត់សិទ្ធិអនុញ្ញាតនេះ ជាដំបូងអ្នកត្រូវបិទអេក្រង់ត្រួតគ្នានៅក្នុង ការកំណត់ &gt; កម្មវិធី"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"បើកការកំណត់"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"សកម្មភាពដំឡើង/លុបការដំឡើងមិនគាំទ្រនៅលើ Wear ទេ"</string>
</resources>
diff --git a/res/values-kn-rIN-watch/strings.xml b/res/values-kn-rIN-watch/strings.xml
new file mode 100644
index 00000000..6ed8b36f
--- /dev/null
+++ b/res/values-kn-rIN-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"ನಿರಾಕರಿಸಿ, ಮತ್ತೆ ಕೇಳಬೇಡಿ"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"ಸಿಸ್ಟಂ ಅಪ್ಲಿಕೇಶನ್‌‌ಗಳನ್ನು ತೋರಿಸು"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
+</resources>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
index 9ff55f9f..298b7cfd 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn-rIN/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"ಪರದೆ ಆವರಿಕೊಳ್ಳುವಿಕೆಯನ್ನು ಪತ್ತೆಹಚ್ಚಲಾಗಿದೆ"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"ಈ ಅನುಮತಿ ಸೆಟ್ಟಿಂಗ್ ಬದಲಾಯಿಸಲು, ನೀವು ಮೊದಲು ಸೆಟ್ಟಿಂಗ್‌ಗಳು &gt; ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಂದ ಪರದೆ ಆವರಿಸಿಕೊಳ್ಳುವಿಕೆಯನ್ನು ಆಫ್ ಮಾಡಬೇಕು"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"ಸೆಟ್ಟಿಂಗ್‍ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"ಸ್ಥಾಪಿಸುವಿಕೆ/ಅಸ್ಥಾಪಿಸುವಿಕೆ ಕ್ರಿಯೆಗಳು Wear ನಲ್ಲಿ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
</resources>
diff --git a/res/values-ko-watch/strings.xml b/res/values-ko-watch/strings.xml
new file mode 100644
index 00000000..0bdafac3
--- /dev/null
+++ b/res/values-ko-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"거부 및 다시 묻지 않음"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"시스템 앱 보기"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"변경할 수 없음"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"사용"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"사용 안함"</string>
+</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 34a58a8d..d4bd8cf9 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"화면 오버레이 감지됨"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"이 권한 설정을 변경하려면 먼저 설정 &gt; 앱에서 화면 오버레이를 사용하지 않도록 설정해야 합니다."</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"설정 열기"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear에서 지원하지 않는 설치/제거 작업입니다."</string>
</resources>
diff --git a/res/values-ky-rKG-watch/strings.xml b/res/values-ky-rKG-watch/strings.xml
new file mode 100644
index 00000000..74a3b8b3
--- /dev/null
+++ b/res/values-ky-rKG-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Баш тарам, экинчи суралбасын"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Тутум колдонмолорун көрсөтүү"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Өзгөртүүгө болбойт"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ИШТЕТИЛГЕН"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ӨЧҮРҮЛГӨН"</string>
+</resources>
diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml
index 0716c2fa..c1ebdde4 100644
--- a/res/values-ky-rKG/strings.xml
+++ b/res/values-ky-rKG/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Экран кабатталышы аныкталды"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Бул уруксаттын жөндөөсүн өзгөртүү үчүн, адегенде Жөндөөлөр &gt; Колдонмолордон экрандын кабатталышын өчүрүңүз"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Жөндөөлөрдү ачуу"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Тагынма"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Орнотуу/чыгарып салуу аракеттери Тагынмада колдоого алынбайт."</string>
</resources>
diff --git a/res/values-lo-rLA-watch/strings.xml b/res/values-lo-rLA-watch/strings.xml
new file mode 100644
index 00000000..e362c39f
--- /dev/null
+++ b/res/values-lo-rLA-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"ປະ​ຕິ​ເສດ, ຢ່າ​ຖາມ​ອີກ"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"ສະ​ແດງ​ແອັບ​ລະ​ບົບ"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"ບໍ່​ສາ​ມາດ​ປ່ຽນ​ແປງ​ໄດ້"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ເປີດໃຊ້ງານ​ແລ້ວ"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ປິດໃຊ້ງານແລ້ວ"</string>
+</resources>
diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml
index 4e0203be..7c67c2ce 100644
--- a/res/values-lo-rLA/strings.xml
+++ b/res/values-lo-rLA/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"ກວດ​ພົບ​ການ​ວາງ​ຊ້ອນ​ໜ້າ​ຈໍ​ແລ້ວ"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"ເພື່ອ​ປ່ຽນ​ແປງ​ການ​ຕັ້ງ​ຄ່າ​ການ​ອະ​ນຸ​ຍາດ​ນີ້, ກ່ອນ​ອື່ນ​ໝົດ​ທ່ານ​ຕ້ອງ​ປິດ​ການ​ວາງ​ຊ້ອນ​ໜ້າ​ຈໍ​ຈາກ​ແອັບ​ການ​ຕັ້ງ​ຄ່າ"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"ເປີດການຕັ້ງຄ່າ"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"ຕິດ​ຕັ້ງ/ຖອນ​ຕິດ​ຕັ້ງ​ການ​ກະ​ທຳ​ທີ່​ບໍ່​ຮອງ​ຮັບ​ຢູ່​ໃນ Wear."</string>
</resources>
diff --git a/res/values-lt-watch/strings.xml b/res/values-lt-watch/strings.xml
new file mode 100644
index 00000000..c10c5e8f
--- /dev/null
+++ b/res/values-lt-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Atmesti, daugiau neklausti"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Rodyti sistemos programas"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Negalima pakeisti"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ĮGALINTAS"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"IŠJUNGTAS"</string>
+</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index c8897229..2ce9c3a2 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -120,4 +120,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Aptikta ekrano perdanga"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Jei norite pakeisti šį leidimo nustatymą, pirmiausia turite išjungti ekrano perdangą skiltyje „Nustatymai &gt; Programos“"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Atidaryti nustatymus"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Diegimo / pašalinimo veiksmai nepalaikomi sistemoje „Wear“."</string>
</resources>
diff --git a/res/values-lv-watch/strings.xml b/res/values-lv-watch/strings.xml
new file mode 100644
index 00000000..aeb3c045
--- /dev/null
+++ b/res/values-lv-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Neatļaut un vairs nejautāt"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>. no <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Rādīt sistēmas lietotnes"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Nevar mainīt"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"IESPĒJOTS"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ATSPĒJOTS"</string>
+</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 27b71cd0..718c5a5f 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -119,4 +119,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Konstatēts ekrāna pārklājums"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Lai mainītu šo atļaujas iestatījumu, vispirms sadaļā “Iestatījumi un lietotnes” izslēdziet ekrāna pārklājumu."</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Atvērt iestatījumus"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear ierīcē netiek atbalstīta instalēšana/atinstalēšana."</string>
</resources>
diff --git a/res/values-mk-rMK-watch/strings.xml b/res/values-mk-rMK-watch/strings.xml
new file mode 100644
index 00000000..d23ce70d
--- /dev/null
+++ b/res/values-mk-rMK-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Одбиј, не прашувај повторно"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Прикажи ги системските апликации"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Не може да се смени"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ОВОЗМОЖЕНО"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ОНЕВОЗМОЖЕНО"</string>
+</resources>
diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml
index 5681b0e6..c7cac3f8 100644
--- a/res/values-mk-rMK/strings.xml
+++ b/res/values-mk-rMK/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Откривме преклопување на екранот"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"За да ја измените оваа поставка за дозвола, прво мора да го исклучите преклопувањето на екранот од Поставки &gt; Апликации"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Отвори поставки"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Дејствата инсталирај/деинсталирај не се поддржани на Wear."</string>
</resources>
diff --git a/res/values-ml-rIN-watch/strings.xml b/res/values-ml-rIN-watch/strings.xml
new file mode 100644
index 00000000..b5056315
--- /dev/null
+++ b/res/values-ml-rIN-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"നിരസിക്കുക, വീണ്ടും ആവശ്യപ്പെടരുത്"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"സിസ്റ്റം ആപ്‌സ് കാണിക്കുക"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"മാറ്റാനാവില്ല"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"പ്രവർത്തനക്ഷമമാക്കി"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"പ്രവർത്തനരഹിതമാക്കി"</string>
+</resources>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
index 55a3d09a..7436447b 100644
--- a/res/values-ml-rIN/strings.xml
+++ b/res/values-ml-rIN/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"സ്ക്രീൻ ഓവർലേ കണ്ടെത്തി"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"ഈ അനുമതി ക്രമീകരണം മാറ്റുന്നതിന്, ക്രമീകരണം &gt; ആപ്സ് എന്നതിൽ നിന്ന് നിങ്ങളാദ്യം സ്ക്രീൻ ഓവർലേ ഓഫാക്കേണ്ടതാണ്"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"ക്രമീകരണം തുറക്കുക"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"ഇൻസ്റ്റാളോ അൺഇൻസ്റ്റാളോ ചെയ്യുന്നതിന് Wear-ൽ പിന്തുണയില്ല."</string>
</resources>
diff --git a/res/values-mn-rMN-watch/strings.xml b/res/values-mn-rMN-watch/strings.xml
new file mode 100644
index 00000000..38c8c9a2
--- /dev/null
+++ b/res/values-mn-rMN-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Татгалзах, дахин бүү асуугаарай"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Системийн апп-ыг харуулах"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Өөрчлөх боломжгүй"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ИДЭВХЖҮҮЛСЭН"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ИДЭВХГҮЙ БОЛГОСОН"</string>
+</resources>
diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml
index 3bce33e9..c7d5431e 100644
--- a/res/values-mn-rMN/strings.xml
+++ b/res/values-mn-rMN/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Дэлгэцийн давхарга илрүүллээ"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Зөвшөөрлийн тохиргоог өөрчлөхийн тулд, эхлээд Тохиргоо ба Апп хэсгээс дэлгэцийн давхаргыг унтраана уу."</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Тохиргоог нээх"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Суулгах/Устгах үйлдлийг Wear дэмжээгүй."</string>
</resources>
diff --git a/res/values-mr-rIN-watch/strings.xml b/res/values-mr-rIN-watch/strings.xml
new file mode 100644
index 00000000..55b6dd33
--- /dev/null
+++ b/res/values-mr-rIN-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"नकार द्या, पुन्हा विचारू नका"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"सिस्टीम अॅप्स दर्शवा"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"बदलू शकत नाही"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"सक्षम केले"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"अक्षम केले"</string>
+</resources>
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml
index b4a3049f..33329489 100644
--- a/res/values-mr-rIN/strings.xml
+++ b/res/values-mr-rIN/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"स्क्रीन आच्छादन आढळले"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"हे परवानगी सेटिंग बदलण्‍यासाठी, आपल्‍याला सेटिंग्ज &gt; Apps मधून स्क्रीन आच्छादन बंद करावे लागेल"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"सेटिंग्ज उघडा"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"स्थापित करा/विस्थापित करा क्रिया Wear वर समर्थित नाहीत."</string>
</resources>
diff --git a/res/values-ms-rMY-watch/strings.xml b/res/values-ms-rMY-watch/strings.xml
new file mode 100644
index 00000000..b69b711d
--- /dev/null
+++ b/res/values-ms-rMY-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Tolak, jangan tanya lagi"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Tunjukkan apl sistem"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Tidak dpt diubah"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"DIDAYAKAN"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DILUMPUHKAN"</string>
+</resources>
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml
index 1dbe2a5c..c524a9af 100644
--- a/res/values-ms-rMY/strings.xml
+++ b/res/values-ms-rMY/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Tindanan skrin dikesan"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Untuk menukar tetapan kebenaran ini, anda perlu mematikan tindanan skrin daripada Tetapan &gt; Apl terlebih dahulu"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Buka tetapan"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Tindakan Pasang/Nyahpasang tidak disokong pada Wear."</string>
</resources>
diff --git a/res/values-my-rMM-watch/strings.xml b/res/values-my-rMM-watch/strings.xml
new file mode 100644
index 00000000..1babba21
--- /dev/null
+++ b/res/values-my-rMM-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"ငြင်းပယ်သည်၊ ထပ်မမေးပါနှင့်"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"စနစ်အပ်ဖ်များ ပြသရန်"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"ပြောင်းလဲ မရနိုင်ပါ"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ဖွင့်ထား"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ပိတ်ထား"</string>
+</resources>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
index 401f7280..818d349b 100644
--- a/res/values-my-rMM/strings.xml
+++ b/res/values-my-rMM/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"မျက်နှာပြင် ထပ်ပေးမှုကို ရှာတွေ့ခဲ့"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"ဒီခွင့်ပြုချက် ဆက်တင်ကို ပြောင်းရန်၊ သင်ဟာ ဦးစွာ ဆက်တင်များ &gt; Appများ ထဲတွင် မျက်နှာပြင် ထပ်ပေးမှုကို ပိတ်လိုက်ရန် လိုမယ်"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"ဆက်တင်းများ ဖွင့်ရန်"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android ဆောင်စရာ"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear ပေါ်တွင် ထည့်သွင်းခြင်း/ဖြုတ်ခြင်း လုပ်ဆောင်ချက်များကို မပံ့ပိုးထားပါ။"</string>
</resources>
diff --git a/res/values-nb-watch/strings.xml b/res/values-nb-watch/strings.xml
new file mode 100644
index 00000000..d2c99f3f
--- /dev/null
+++ b/res/values-nb-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Avvis, ikke spør igjen"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Vis systemapper"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Kan ikke endres"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"SLÅTT PÅ"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"SLÅTT AV"</string>
+</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 7d72c921..8d74eb1a 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Skjermoverlegg oppdaget"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"For å endre denne tillatelsesinnstilingen må du først slå av skjermoverlegget fra Innstillinger &gt; Apper"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Åpne innstillingene"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Handlingene for å installere og avinstallere er ikke støttet på Wear."</string>
</resources>
diff --git a/res/values-ne-rNP-watch/strings.xml b/res/values-ne-rNP-watch/strings.xml
new file mode 100644
index 00000000..89e48dd4
--- /dev/null
+++ b/res/values-ne-rNP-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"अस्वीकार गर्नुहोस्, फेरि नसोध्नुहोस्"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"प्रणाली अनुप्रयोगहरू देखाउनुहोस्"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"परिवर्तन गर्न सकिँदैन"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"सक्षम गरियो"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"असक्षम गरियो"</string>
+</resources>
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml
index 9fe7cf8f..8e0c4243 100644
--- a/res/values-ne-rNP/strings.xml
+++ b/res/values-ne-rNP/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"स्क्रिन ओभरले पत्ता लाग्यो"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"यो अनुमति सेटिङ परिवर्तन गर्न, तपाईँले पहिला सेटिङ अनुप्रयोगबाट स्क्रिन ओभरले बन्द गर्नु पर्दछ।"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"सेटिङहरू खोल्नुहोस्"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear मा स्थापना/स्थापना रद्द गर्ने कार्यहरू समर्थित छैनन्।"</string>
</resources>
diff --git a/res/values-nl-watch/strings.xml b/res/values-nl-watch/strings.xml
new file mode 100644
index 00000000..820875e3
--- /dev/null
+++ b/res/values-nl-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Weigeren, niet meer vragen"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Systeem-apps weergeven"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Niet aanpasbaar"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"INGESCHAKELD"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"UITGESCHAKELD"</string>
+</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index c16efaf1..c2c3fe4b 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Schermoverlay gedetecteerd"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Als u deze instelling voor rechten wilt wijzigen, moet u eerst de schermoverlay uitschakelen via \'Instellingen\' &gt; \'Apps\'"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Instellingen openen"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Acties voor installeren/verwijderen niet ondersteund op Wear"</string>
</resources>
diff --git a/res/values-pa-rIN-watch/strings.xml b/res/values-pa-rIN-watch/strings.xml
new file mode 100644
index 00000000..d6cfe6c8
--- /dev/null
+++ b/res/values-pa-rIN-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"ਅਸਵੀਕਾਰ ਕਰੋ, ਦੁਬਾਰਾ ਨਾ ਪੁੱਛੋ"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"ਸਿਸਟਮ ਐਪਸ ਦਿਖਾਓ"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"ਬਦਲਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ਸਮਰਥਿਤ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ਅਸਮਰਥਿਤ ਕੀਤਾ ਗਿਆ"</string>
+</resources>
diff --git a/res/values-pa-rIN/strings.xml b/res/values-pa-rIN/strings.xml
index 772258fb..ec19acb5 100644
--- a/res/values-pa-rIN/strings.xml
+++ b/res/values-pa-rIN/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"ਸਕਰੀਨ ਓਵਰਲੇਅ ਲੱਭ ਗਿਆ"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"ਇਸ ਇਜ਼ਾਜਤ ਸੈਟਿੰਗ ਨੂੰ ਬਦਲਣ ਲਈ; ਤੁਹਾਨੂੰ ਪਹਿਲਾਂ ਸੈਟਿੰਗਜ਼ ਅਤੇ ਐਪਸ ਤੋਂ ਸਕ੍ਰੀਨ ਓਵਰਲੇਅ ਬੰਦ ਕਰਨਾ ਪਵੇਗਾ"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"ਸੈਟਿੰਗਜ਼ ਖੋਲ੍ਹੋ"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android ਵੀਅਰ"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"ਵੀਅਰ \'ਤੇ ਸਥਾਪਿਤ ਕਰੋ/ਸਥਾਪਨਾ ਰੱਦ ਕਰੋ ਕਾਰਵਾਈਆਂ ਸਮਰਥਿਤ ਨਹੀਂ ਹਨ।"</string>
</resources>
diff --git a/res/values-pl-watch/strings.xml b/res/values-pl-watch/strings.xml
new file mode 100644
index 00000000..2bf7d356
--- /dev/null
+++ b/res/values-pl-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Odmów i nie pytaj ponownie"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Pokaż aplikacje systemowe"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Nie można zmienić"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"WŁ."</string>
+ <string name="generic_disabled" msgid="576339310027394867">"WYŁĄCZONE"</string>
+</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 0e9a3314..be271263 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -120,4 +120,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Wykryto nakładkę ekranową"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Aby zmodyfikować te uprawnienia, musisz najpierw wyłączyć nakładkę ekranową, klikając Ustawienia &gt; Aplikacje"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Otwórz ustawienia"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear nie obsługuje instalowania ani odinstalowywania."</string>
</resources>
diff --git a/res/values-pt-rBR-watch/strings.xml b/res/values-pt-rBR-watch/strings.xml
new file mode 100644
index 00000000..cb228f9d
--- /dev/null
+++ b/res/values-pt-rBR-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Negar e não perguntar de novo"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Mostrar apps do sistema"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Impossível alterar"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ATIVADA"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DESATIVADA"</string>
+</resources>
diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml
index 713a8aa3..ad029b0d 100644
--- a/res/values-pt-rBR/strings.xml
+++ b/res/values-pt-rBR/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Sobreposição de tela detectada"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Para alterar a configuração dessa permissão, você deve primeiro desativar a sobreposição de tela em \"Config.\" &gt; \"Apps\""</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Abrir configurações"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"As ações de instalar/desinstalar não são compatíveis com o Android Wear."</string>
</resources>
diff --git a/res/values-pt-rPT-watch/strings.xml b/res/values-pt-rPT-watch/strings.xml
new file mode 100644
index 00000000..e8d1bda4
--- /dev/null
+++ b/res/values-pt-rPT-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Recusar e não perguntar nov."</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Mostrar aplicações do sistema"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Não pode ser alterado"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ATIVADO"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DESATIVADO"</string>
+</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index f38aac62..5d6931b9 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Sobreposição de ecrã detetada"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Para alterar esta definição de autorização, primeiro tem de desativar a sobreposição do ecrã em Definições &gt; Aplicações"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Abrir definições"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"As ações de instalar/desinstalar não são compatíveis com o Android Wear."</string>
</resources>
diff --git a/res/values-pt-watch/strings.xml b/res/values-pt-watch/strings.xml
new file mode 100644
index 00000000..cb228f9d
--- /dev/null
+++ b/res/values-pt-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Negar e não perguntar de novo"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Mostrar apps do sistema"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Impossível alterar"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ATIVADA"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DESATIVADA"</string>
+</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 713a8aa3..ad029b0d 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Sobreposição de tela detectada"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Para alterar a configuração dessa permissão, você deve primeiro desativar a sobreposição de tela em \"Config.\" &gt; \"Apps\""</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Abrir configurações"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"As ações de instalar/desinstalar não são compatíveis com o Android Wear."</string>
</resources>
diff --git a/res/values-ro-watch/strings.xml b/res/values-ro-watch/strings.xml
new file mode 100644
index 00000000..5ff2575b
--- /dev/null
+++ b/res/values-ro-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Respingeți; nu se mai întreabă"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Afișează aplicațiile de sistem"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Nu se poate modifica"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ACTIVATĂ"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DEZACTIVATĂ"</string>
+</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index eae848e5..1f963c70 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -119,4 +119,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"S-a detectat suprapunerea pe ecran"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Ca să schimbați această setare pentru permisiuni, mai întâi trebuie să dezactivați suprapunerea pe ecran din Setări &gt; Aplicații"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Deschideți setările"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Acțiunile Instalați/Dezinstalați nu sunt acceptate pe Wear."</string>
</resources>
diff --git a/res/values-round/dimens.xml b/res/values-round/dimens.xml
new file mode 100644
index 00000000..bed41ce0
--- /dev/null
+++ b/res/values-round/dimens.xml
@@ -0,0 +1,26 @@
+<?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");
+ 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>
+ <!-- Dimensions for the Grant permissions Confirmation Dialog -->
+ <dimen name="conf_diag_button_container_height">96dp</dimen>
+ <dimen name="conf_diag_2button_margin_side">32dp</dimen>
+ <dimen name="conf_diag_2button_margin_top">10dp</dimen>
+ <!-- On round screens, the message can't be too close to the top or the corners will be
+ clipped. -->
+ <dimen name="conf_diag_min_space_above_message">26dp</dimen>
+
+</resources>
diff --git a/res/values-ru-watch/strings.xml b/res/values-ru-watch/strings.xml
new file mode 100644
index 00000000..309dc244
--- /dev/null
+++ b/res/values-ru-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Запретить и не спрашивать"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Показать системные приложения"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Нельзя изменить"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ВКЛЮЧЕНО"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ОТКЛЮЧЕНО"</string>
+</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index dd270bdc..9cad9cab 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -120,4 +120,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Обнаружены наложения"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Чтобы предоставить или отменить разрешение, сначала отключите наложения. Для этого нажмите \"Настройки &gt; Приложения\"."</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Открыть настройки"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Android Wear не поддерживает установку и удаление."</string>
</resources>
diff --git a/res/values-si-rLK-watch/strings.xml b/res/values-si-rLK-watch/strings.xml
new file mode 100644
index 00000000..b2559567
--- /dev/null
+++ b/res/values-si-rLK-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"ප්‍රතික්ෂේප කරන්න, නැවත අසන්න එපා"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"පද්ධති යෙදුම් පෙන්වන්න"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"වෙනස් කළ නොහැකිය"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"සබලයි"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"අබලයි"</string>
+</resources>
diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml
index 1ab14753..d381abcb 100644
--- a/res/values-si-rLK/strings.xml
+++ b/res/values-si-rLK/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"තිර උඩැතිරියක් අනාවරණය කරන ලදි"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"මෙම අවසර සැකසීම වෙනස් කිරීම සඳහා, ඔබට මුලින්ම සැකසීම් &gt; යෙදුම් වෙතින් තිර උඩැතිරිය අක්‍රිය කර යුතුයි"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"සැකසීම් විවෘත කරන්න"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear මත ස්ථාපන/අස්ථාපනය ක්‍රියා වෙත සහය දක්වන්නේ නැත."</string>
</resources>
diff --git a/res/values-sk-watch/strings.xml b/res/values-sk-watch/strings.xml
new file mode 100644
index 00000000..9b17f9ba
--- /dev/null
+++ b/res/values-sk-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Zamietnuť a už sa nepýtať"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Zobraziť systémové aplikácie"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Nedá sa zmeniť"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"POVOLENÉ"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ZAKÁZANÉ"</string>
+</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 93f55792..213e4481 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -120,4 +120,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Bolo zistené prekrytie obrazovky"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Ak chcete zmeniť nastavenie tohto povolenia, musíte najprv v časti Nastavenia &gt; Aplikácie vypnúť prekrytie obrazovky"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Otvoriť nastavenia"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Systém Wear nepodporuje akciu inštalácie/odinštalovania"</string>
</resources>
diff --git a/res/values-sl-watch/strings.xml b/res/values-sl-watch/strings.xml
new file mode 100644
index 00000000..cd71f48c
--- /dev/null
+++ b/res/values-sl-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Zavrni, ne sprašuj več"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Prikaz sistemskih aplikacij"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Ni mogoče sprem."</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"OMOGOČENO"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ONEMOGOČENO"</string>
+</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 86219831..362693c6 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -120,4 +120,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Zaznano prekrivanje zaslona"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Če želite spremeniti nastavitev tega dovoljenja, morate najprej izklopiti prekrivanje zaslona v »Nastavitve &gt; Aplikacije«"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Odpri nastavitve"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Dejanja namestitve in odstranitve v sistemu Android Wear niso podprta."</string>
</resources>
diff --git a/res/values-sq-rAL-watch/strings.xml b/res/values-sq-rAL-watch/strings.xml
new file mode 100644
index 00000000..213ce5a4
--- /dev/null
+++ b/res/values-sq-rAL-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Refuzoje, mos pyet sërish"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Shfaq aplikacionet e sistemit"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Nuk mund të ndryshohet"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"AKTIVIZUAR"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ÇAKTIVIZUAR"</string>
+</resources>
diff --git a/res/values-sq-rAL/strings.xml b/res/values-sq-rAL/strings.xml
index 1e3d9985..319d6e26 100644
--- a/res/values-sq-rAL/strings.xml
+++ b/res/values-sq-rAL/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Mbivendosja e ekranit u zbulua"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Për të ndryshuar këtë cilësim të lejes, në fillim duhet të çaktivizosh mbivendosjen e ekranit nga Cilësimet &gt; Aplikacionet"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Hap cilësimet"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Teknologjia \"Android\" që vishet"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Instalo/çinstalo veprimet që nuk mbështeten në teknologjinë që vishet."</string>
</resources>
diff --git a/res/values-sr-watch/strings.xml b/res/values-sr-watch/strings.xml
new file mode 100644
index 00000000..e51b35a4
--- /dev/null
+++ b/res/values-sr-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Одбиј и не питај поново"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Прикажи системске апликације"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Не може да се промени"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ОМОГУЋЕНО"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ОНЕМОГУЋЕНО"</string>
+</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 0d1af776..67548d0b 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -119,4 +119,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Откривен је елемент који прекрива садржај екрана"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Да бисте променили подешавање ове дозволе, прво треба да искључите елемент који прекрива садржај екрана у одељку Подешавања &gt; Апликације"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Отвори подешавања"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Радње Инсталирај/Деинсталирај нису подржане у Wear-у."</string>
</resources>
diff --git a/res/values-sv-watch/strings.xml b/res/values-sv-watch/strings.xml
new file mode 100644
index 00000000..66465f4d
--- /dev/null
+++ b/res/values-sv-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Avvisa och fråga inte igen"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Visa systemappar"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Kan inte ändras"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"AKTIVERAD"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"INAKTIVERAD"</string>
+</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index a8bd7e04..faef032f 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Skärmöverlagring har upptäckts"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Innan du kan ändra den här behörighetsinställningen måste du inaktivera skärmöverlagring under Inställningar &gt; Appar"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Öppna inställningarna"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Åtgärder för att installera/avinstallera stöds inte på Wear."</string>
</resources>
diff --git a/res/values-sw-watch/strings.xml b/res/values-sw-watch/strings.xml
new file mode 100644
index 00000000..b4adaca4
--- /dev/null
+++ b/res/values-sw-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Kataa, usiulize tena"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Onyesha programu za mfumo"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Haiwezi kubadilishwa"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"IMEWASHWA"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"IMEZIMWA"</string>
+</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index eb9c1474..d6f775e5 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Imetambua tangazo lililowekelewa juu ya skrini"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Ili kubadilisha mpangilio huu wa ruhusa, ni lazima kwanza uzime tangazo lililowekelewa juu ya skrini kwenye Mipangilio na Programu"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Fungua mipangilio"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Vitendo vya Kusakinisha/Kuondoa haviwezi kutumika kwenye Android Wear."</string>
</resources>
diff --git a/res/values-ta-rIN-watch/strings.xml b/res/values-ta-rIN-watch/strings.xml
new file mode 100644
index 00000000..54c61e7c
--- /dev/null
+++ b/res/values-ta-rIN-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"நிராகரி, மீண்டும் கேட்காதே"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"முறைமைப் பயன்பாடுகளைக் காட்டு"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"மாற்ற முடியாது"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"இயக்கப்பட்டது"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"முடக்கப்பட்டது"</string>
+</resources>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
index 0e3e5809..860e671e 100644
--- a/res/values-ta-rIN/strings.xml
+++ b/res/values-ta-rIN/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"திரையின் மேலே செயல்படும் பயன்பாடுகள் கண்டறியப்பட்டன"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"இந்த அனுமதியை மாற்ற, அமைப்புகள் &gt; பயன்பாடுகள் என்பதற்குச் சென்று, திரையின் மேலே செயல்படும் பயன்பாடுகளை முதலில் முடக்கவும்"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"அமைப்புகளைத் திற"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear இல் நிறுவுதல்/நிறுவல் நீக்குதலுக்கு ஆதரவில்லை."</string>
</resources>
diff --git a/res/values-te-rIN-watch/strings.xml b/res/values-te-rIN-watch/strings.xml
new file mode 100644
index 00000000..e13ba44e
--- /dev/null
+++ b/res/values-te-rIN-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"నిరాకరిస్తున్నాను,ఇక అడగవద్దు"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"సిస్టమ్ అనువర్తనాలను చూపు"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"మార్చడం సాధ్యపడదు"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ప్రారంభించబడింది"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"నిలిపివేయబడింది"</string>
+</resources>
diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml
index de29a0be..ddcfcc50 100644
--- a/res/values-te-rIN/strings.xml
+++ b/res/values-te-rIN/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"స్క్రీన్ అతివ్యాప్తి గుర్తించబడింది"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"ఈ అనుమతి సెట్టింగ్‌ను మార్చడానికి, మీరు ముందుగా సెట్టింగ్‌లు &gt; అనువర్తనాల నుండి స్క్రీన్ అతివ్యాప్తిని ఆఫ్ చేయాలి"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"సెట్టింగ్‌లను తెరువు"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android వేర్"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"వేర్‌లో ఇన్‌స్టాల్/అన్ఇన్‌స్టాల్ చర్యలకు మద్దతు లేదు"</string>
</resources>
diff --git a/res/values-th-watch/strings.xml b/res/values-th-watch/strings.xml
new file mode 100644
index 00000000..ba86f12c
--- /dev/null
+++ b/res/values-th-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"ปฏิเสธ ไม่ต้องถามอีก"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"แสดงแอประบบ"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"ไม่สามารถเปลี่ยน"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"เปิดใช้อยู่"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ปิดใช้อยู่"</string>
+</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 7058a652..8ca2486d 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"ตรวจพบการวางซ้อนหน้าจอ"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"ในการเปลี่ยนแปลงการตั้งค่าสิทธิ์นี้ ก่อนอื่น คุณต้องปิดการวางซ้อนหน้าจอที่การตั้งค่า &gt; แอป"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"เปิดการตั้งค่า"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"ไม่สามารถติดตั้ง/ถอนการติดตั้งบน Wear"</string>
</resources>
diff --git a/res/values-tl-watch/strings.xml b/res/values-tl-watch/strings.xml
new file mode 100644
index 00000000..8885a84f
--- /dev/null
+++ b/res/values-tl-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Tanggihan, huwag nang tatanunging muli"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Ipakita ang mga app ng system"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Hindi mababago"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"NAKA-ENABLE"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"NAKA-DISABLE"</string>
+</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index eb7dbc99..f8eead24 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Natukoy ang overlay ng screen"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Upang baguhin ang setting ng pahintulot na ito, kailangan mo munang i-off ang overlay ng screen mula sa Mga Setting &gt; Mga App"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Buksan ang mga setting"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"I-install/I-uninstall ang mga pagkilos na hindi sinusuportahan sa Wear."</string>
</resources>
diff --git a/res/values-tr-watch/strings.xml b/res/values-tr-watch/strings.xml
new file mode 100644
index 00000000..c7eddced
--- /dev/null
+++ b/res/values-tr-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Reddet, bir daha sorma"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Sistem uygulamalarını göster"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Değiştirilemez"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ETKİN"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"DEVRE DIŞI"</string>
+</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 6b5437b8..e41aa52d 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Ekran yer paylaşımı tespit edildi"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Bu izin ayarını değiştirmek için ilk olarak Ayarlar &gt; Uygulamalar\'dan ekran yer paylaşımını kapatmanız gerekir"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Ayarları aç"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Yükleme/Yüklemeyi Kaldırma işlemleri Wear\'da desteklenmiyor."</string>
</resources>
diff --git a/res/values-uk-watch/strings.xml b/res/values-uk-watch/strings.xml
new file mode 100644
index 00000000..aac71cbe
--- /dev/null
+++ b/res/values-uk-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Відхилити й більше не запитувати"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> з <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Показати системні додатки"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Не можна змінити"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"УВІМКНЕНО"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ВИМКНЕНО"</string>
+</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 1450c9d6..a78d828e 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -120,4 +120,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Виявлено накладання на екрані"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Щоб змінити налаштування цього дозволу, спершу вимкніть накладання на екрані в меню \"Налаштування\" &gt; \"Додатки\""</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Відкрити налаштування"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Функція \"Встановити/видалити\" не підтримується на пристроях Android Wear."</string>
</resources>
diff --git a/res/values-ur-rPK-watch/strings.xml b/res/values-ur-rPK-watch/strings.xml
new file mode 100644
index 00000000..f3746d50
--- /dev/null
+++ b/res/values-ur-rPK-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"انکار کریں، دوبارہ مت پوچھیں"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"سسٹم ایپس دکھائیں"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"ناقابل تبدیل"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"فعال"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"غیر فعال"</string>
+</resources>
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml
index 2ed1a3dd..51aa8e26 100644
--- a/res/values-ur-rPK/strings.xml
+++ b/res/values-ur-rPK/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"اسکرین اورلے کا پتہ چلا ہے"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"‏اس اجازت کی ترتیب کو تبدیل کرنے کیلئے آپ کو پہلے ترتیبات &gt; Apps سے سکرین اورلے آف کرنا ہوگا"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"ترتیبات کھولیں"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"‏Wear پر غیر تعاون یافتہ کاروائیاں انسٹال/ان انسٹال کریں۔"</string>
</resources>
diff --git a/res/values-uz-rUZ-watch/strings.xml b/res/values-uz-rUZ-watch/strings.xml
new file mode 100644
index 00000000..dca320a9
--- /dev/null
+++ b/res/values-uz-rUZ-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Rad etilsin va boshqa so‘ralmasin"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Tizim ilovalarini ko‘rsatish"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"O‘zgartirilmaydi"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"YONIQ"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"O‘CHIQ"</string>
+</resources>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
index cebee29a..aba004e2 100644
--- a/res/values-uz-rUZ/strings.xml
+++ b/res/values-uz-rUZ/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Ekran ustidan ochiladigan ilova aniqlandi"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Bu ruxsatnoma parametrini o‘zgartirish uchun avval Sozlamalar &gt; Ilovalar bo‘limidan ekran ustidan ochilish funksiyasini o‘chirib qo‘ying"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Sozlamalarni ochish"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear qurilmasi o‘rnatish/o‘chirish amallarini qo‘llab-quvvatlamaydi."</string>
</resources>
diff --git a/res/values-vi-watch/strings.xml b/res/values-vi-watch/strings.xml
new file mode 100644
index 00000000..c342949e
--- /dev/null
+++ b/res/values-vi-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Từ chối, không hỏi lại"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Hiển thị ứng dụng hệ thống"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Ko thể thay đổi"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"ĐÃ BẬT"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"ĐÃ TẮT"</string>
+</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 69bc823b..6ca7e0ce 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Đã phát hiện lớp phủ màn hình"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Để thay đổi cài đặt quyền này, trước tiên bạn phải tắt lớp phủ màn hình từ Cài đặt &gt; Ứng dụng"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Mở cài đặt"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Không hỗ trợ tác vụ Cài đặt/Gỡ cài đặt trên Wear."</string>
</resources>
diff --git a/res/values-watch/attrs.xml b/res/values-watch/attrs.xml
new file mode 100644
index 00000000..e220f4c8
--- /dev/null
+++ b/res/values-watch/attrs.xml
@@ -0,0 +1,35 @@
+<?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");
+ 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>
+ <!-- START: Ported from WearableSupport -->
+ <declare-styleable name="CircledImageView">
+ <attr name="android:src" />
+ <attr name="circle_color" format="color" />
+ <attr name="circle_radius" format="dimension" />
+ <attr name="circle_radius_pressed" format="dimension" />
+ <attr name="circle_border_width" format="dimension" />
+ <attr name="circle_border_color" format="color" />
+ <attr name="circle_padding" format="dimension" />
+ <attr name="shadow_width" format="dimension" />
+ <attr name="image_circle_percentage" format="dimension" />
+ <attr name="image_horizontal_offcenter_percentage" format="dimension" />
+ <attr name="image_tint" format="color" />
+ <attr name="circle_radius_percent" format="fraction" />
+ <attr name="circle_radius_pressed_percent" format="fraction" />
+ </declare-styleable>
+ <!-- END: Ported from WearableSupport -->
+</resources>
diff --git a/res/values-watch/colors.xml b/res/values-watch/colors.xml
new file mode 100644
index 00000000..b81d6e3b
--- /dev/null
+++ b/res/values-watch/colors.xml
@@ -0,0 +1,36 @@
+<?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");
+ 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="grant_permissions_app_color">@color/grant_permissions_white_text_alpha_100</color>
+ <color name="grant_permissions_progress_color">@color/grant_permissions_white_text_alpha_100</color>
+ <color name="grant_permissions_title_color">@color/grant_permissions_white_text_alpha_70</color>
+
+ <color name="grant_permissions_white_text_alpha_100">@color/off_white</color>
+ <color name="grant_permissions_white_text_alpha_70">#b2eeeeee</color>
+
+ <color name="permissions_settings_item_color">#FFFFFFFF</color>
+
+ <color name="off_white">#ffeeeeee</color>
+
+ <color name="primary_text_light">#424242</color>
+
+ <!-- Copied from wearable support -->
+ <color name="circular_button_disabled">#757575</color>
+
+ <!-- Copied from wearable Clockwork Settings -->
+ <color name="cw_dark_gray">#424242</color>
+</resources>
diff --git a/res/values-watch/dimens.xml b/res/values-watch/dimens.xml
new file mode 100644
index 00000000..96f32148
--- /dev/null
+++ b/res/values-watch/dimens.xml
@@ -0,0 +1,57 @@
+<?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");
+ 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="grant_permissions_app_icon_size">20dp</dimen>
+ <dimen name="grant_permissions_app_icon_margin_top">6dp</dimen>
+
+ <dimen name="grant_permissions_app_breadcrumb_margin_top">6dp</dimen>
+ <dimen name="grant_permissions_title_margin_top">6dp</dimen>
+ <dimen name="grant_permissions_message_side_padding">32dp</dimen>
+
+ <dimen name="action_dialog_z">16dp</dimen>
+
+ <!-- Dimensions for the Grant permissions Confirmation Dialog -->
+ <dimen name="conf_diag_floating_height">16dp</dimen>
+ <dimen name="conf_diag_button_container_top_margin">6dp</dimen>
+ <dimen name="conf_diag_button_container_height">72dp</dimen>
+ <dimen name="conf_diag_2button_margin_side">16dp</dimen>
+ <dimen name="conf_diag_2button_margin_top">9dp</dimen>
+ <dimen name="conf_diag_3button_padding_side">32dp</dimen>
+ <dimen name="conf_diag_3button_padding_bottom">22dp</dimen>
+ <dimen name="conf_diag_content_padding_top">6dp</dimen>
+ <!-- On square screens, the message can be at the top of the screen. -->
+ <dimen name="conf_diag_min_space_above_message">0dp</dimen>
+
+
+ <!-- START: Ported values -->
+ <item name="default_settings_circle_radius_percent" format="fraction" type="dimen">40%</item>
+ <item name="selected_settings_circle_radius_percent" format="fraction" type="dimen">50%</item>
+ <dimen name="round_content_padding_left">40dp</dimen>
+ <dimen name="round_content_padding_right">24dp</dimen>
+ <dimen name="content_padding_left">12dp</dimen>
+ <dimen name="settings_wearable_list_view_vertical_padding_round">14dp</dimen>
+ <dimen name="setting_header_extra_line_height">16dp</dimen>
+ <dimen name="setting_long_header_text_size">20dp</dimen>
+ <dimen name="settings_header_base_height">50dp</dimen>
+ <dimen name="settings_header_top_margin">14dp</dimen>
+ <dimen name="settings_header_top_margin_circular">18dp</dimen>
+ <dimen name="settings_header_top_margin_multiline">6dp</dimen>
+ <dimen name="settings_header_top_margin_circular_multiline">16dp</dimen>
+ <dimen name="setting_short_header_text_size">24dp</dimen>
+ <dimen name="settings_text_margin_left">10dp</dimen>
+ <!-- END: Ported values -->
+</resources>
diff --git a/res/values-watch/integers.xml b/res/values-watch/integers.xml
new file mode 100644
index 00000000..365ac3ab
--- /dev/null
+++ b/res/values-watch/integers.xml
@@ -0,0 +1,22 @@
+<?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");
+ 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- START: Ported values -->
+ <integer name="short_title_length">13</integer>
+ <integer name="char_limit_per_line">18</integer>
+ <!-- END: Ported values -->
+</resources>
diff --git a/res/values-watch/strings.xml b/res/values-watch/strings.xml
new file mode 100644
index 00000000..82fe4ae9
--- /dev/null
+++ b/res/values-watch/strings.xml
@@ -0,0 +1,37 @@
+<?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");
+ 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Title for the dialog button to deny a permission grant and never ask the user again. [CHAR LIMIT=29]-->
+ <string name="grant_dialog_button_deny_dont_ask_again">Deny, don\'t ask again</string>
+
+ <!-- Template for the current permission from the total number of permissions. -->
+ <string name="current_permission_template">
+ <xliff:g id="current_permission_index" example="1">%1$s</xliff:g> /
+ <xliff:g id="permission_count" example="2">%2$s</xliff:g>
+ </string>
+
+ <!-- Preference row title for showing system apps. -->
+ <string name="preference_show_system_apps">Show system apps</string>
+
+ <!-- Summary of a permission switch when it's enforced by policy [CHAR LIMIT=17] -->
+ <string name="permission_summary_enforced_by_policy">Can\'t be changed</string>
+
+ <!-- Generic text to indicate that a setting is enabled. Should be in all caps. [CHAR LIMIT=40] -->
+ <string name="generic_enabled">ENABLED</string>
+ <!-- Generic text to indicate that a setting is disabled. Should be in all caps. [CHAR LIMIT=40] -->
+ <string name="generic_disabled">DISABLED</string>
+</resources>
diff --git a/res/values-watch/styles.xml b/res/values-watch/styles.xml
new file mode 100644
index 00000000..01ab90eb
--- /dev/null
+++ b/res/values-watch/styles.xml
@@ -0,0 +1,49 @@
+<?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");
+ 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="Theme.DialogWhenLarge" parent="@android:style/Theme.DeviceDefault.NoActionBar"/>
+
+ <!-- START: Ported values -->
+ <style name="TextAppearance.Wearable.Small" parent="android:TextAppearance.Medium">
+ <item name="android:textSize">16sp</item>
+ <item name="android:textColor">@color/primary_text_light</item>
+ </style>
+
+ <style name="TextView.Small" parent="@android:style/Widget.Holo.Light">
+ <item name="android:fontFamily">sans-serif-condensed</item>
+ <item name="android:textAppearance">@style/TextAppearance.Wearable.Small</item>
+ </style>
+
+ <style name="TextView.Small.Light">
+ <item name="android:fontFamily">sans-serif-condensed-light</item>
+ <item name="android:textAppearance">@style/TextAppearance.Wearable.Small</item>
+ </style>
+
+ <style name="TextAppearance.Settings.Label" parent="android:TextAppearance.Medium">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">#FFFFFFFF</item>
+ </style>
+
+ <style name="TextAppearance.Settings.Label.Large">
+ <item name="android:textSize">16sp</item>
+ </style>
+
+ <style name="TextView.Settings.Label" parent="TextView.Small.Light">
+ <item name="android:textAppearance">@style/TextAppearance.Settings.Label</item>
+ </style>
+ <!-- END: Ported values -->
+</resources>
diff --git a/res/values-watch/themes.xml b/res/values-watch/themes.xml
new file mode 100644
index 00000000..dea42907
--- /dev/null
+++ b/res/values-watch/themes.xml
@@ -0,0 +1,64 @@
+<?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");
+ ~ 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="Settings" parent="@android:style/Theme.DeviceDefault.NoActionBar">
+ <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Permissions</item>
+ <item name="android:windowBackground">@color/cw_dark_gray</item>
+ <item name="android:colorBackground">@color/cw_dark_gray</item>
+ </style>
+
+ <style name="GrantPermissions" parent="Settings">
+ <item name="android:windowIsFloating">true</item>
+ <item name="android:windowElevation">@dimen/action_dialog_z</item>
+ <item name="android:windowSwipeToDismiss">false</item>
+ </style>
+
+ <style name="GrantPermissions.BreadcrumbText">
+ <item name="android:fontFamily">sans-serif-condensed</item>
+ <item name="android:textSize">16sp</item>
+ <item name="android:textColor">@color/grant_permissions_progress_color</item>
+ </style>
+
+ <style name="GrantPermissions.TitleText">
+ <item name="android:fontFamily">sans-serif-condensed-light</item>
+ <item name="android:textSize">18sp</item>
+ <item name="android:textColor">@color/grant_permissions_title_color</item>
+ <item name="android:lineSpacingMultiplier">1.221</item>
+ </style>
+
+ <!-- Copied from WearableSupport lib -->
+ <style name="TextAppearance.WearDiag" parent="android:TextAppearance.Medium">
+ <item name="android:textColor">#FFFFFF</item>
+ <item name="android:textSize">16sp</item>
+ </style>
+ <style name="TextAppearance.WearDiag.Button">
+ <item name="android:textSize">16sp</item>
+ </style>
+ <style name="Widget.WearDiag.Button" parent="@android:style/Widget.DeviceDefault.Button">
+ <item name="android:fontFamily">sans-serif-condensed-light</item>
+ <item name="android:gravity">center_vertical|left</item>
+ <item name="android:textAppearance">@style/TextAppearance.WearDiag.Button</item>
+ <item name="android:background">@android:color/transparent</item>
+ <item name="android:minLines">1</item>
+ <item name="android:maxLines">3</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:layout_height">60dp</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:drawablePadding">12dp</item>
+ </style>
+</resources>
diff --git a/res/values-zh-rCN-watch/strings.xml b/res/values-zh-rCN-watch/strings.xml
new file mode 100644
index 00000000..d6e64c34
--- /dev/null
+++ b/res/values-zh-rCN-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"拒绝,不要再询问"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"显示系统应用"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"无法更改"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"已启用"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"已停用"</string>
+</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index ab5925a6..08c9134b 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"检测到屏幕叠加层"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"要更改此权限设置,您必须首先在“设置”&gt;“应用”中关闭屏幕叠加层"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"打开设置"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear 不支持安装/卸载操作。"</string>
</resources>
diff --git a/res/values-zh-rHK-watch/strings.xml b/res/values-zh-rHK-watch/strings.xml
new file mode 100644
index 00000000..9c21b2ab
--- /dev/null
+++ b/res/values-zh-rHK-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"拒絕,不要再詢問"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"顯示系統應用程式"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"不可變更"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"已啟用"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"已停用"</string>
+</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 947ba084..56ea1404 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"已偵測到螢幕重疊功能"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"如要變更此權限設定,請先前往 [設定] &gt; [應用程式],以關閉螢幕重疊功能"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"開啟設定"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear 不支援安裝/解除安裝操作。"</string>
</resources>
diff --git a/res/values-zh-rTW-watch/strings.xml b/res/values-zh-rTW-watch/strings.xml
new file mode 100644
index 00000000..4c9245d1
--- /dev/null
+++ b/res/values-zh-rTW-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"拒絕且不要再詢問"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"顯示系統應用程式"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"無法變更"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"已啟用"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"已停用"</string>
+</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 2c9861f4..7c7f732c 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"偵測到畫面重疊圖層"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"如要變更這項權限設定,您必須先依序前往 [設定] &gt; [應用程式],關閉裝置畫面重疊圖層"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"開啟設定"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Wear 不支援安裝及解除安裝操作。"</string>
</resources>
diff --git a/res/values-zu-watch/strings.xml b/res/values-zu-watch/strings.xml
new file mode 100644
index 00000000..82f45df9
--- /dev/null
+++ b/res/values-zu-watch/strings.xml
@@ -0,0 +1,25 @@
+<?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");
+ 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="grant_dialog_button_deny_dont_ask_again" msgid="5828565432145544298">"Yenqaba, ungangibuzi futhi"</string>
+ <string name="current_permission_template" msgid="6691830243038105737">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
+ <string name="preference_show_system_apps" msgid="7042886929865431207">"Bonisa izinhlelo zokusebenza zesistimu"</string>
+ <string name="permission_summary_enforced_by_policy" msgid="9002523259681588936">"Akukwazi ukushintshwa"</string>
+ <string name="generic_enabled" msgid="5221039415230005888">"KUNIKWE AMANDLA"</string>
+ <string name="generic_disabled" msgid="576339310027394867">"KUKHUTSHAZIWE"</string>
+</resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index f0524bab..acd9b5b2 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -118,4 +118,6 @@
<string name="screen_overlay_title" msgid="3021729846864038529">"Kutholwe imbondela yesikrini"</string>
<string name="screen_overlay_message" msgid="2141944461571677331">"Ukuze uguqule lesi silungiselelo semvume, kuzomele uqale uvale imbondela yesikrini kusukela ku-Izilungiselelo &gt; Izinhlelo zokusebenza"</string>
<string name="screen_overlay_button" msgid="4344544843349937743">"Vula izilungiselelo"</string>
+ <string name="wear_not_allowed_dlg_title" msgid="8104666773577525713">"I-Android Wear"</string>
+ <string name="wear_not_allowed_dlg_text" msgid="1618381127237173068">"Izenzo zokufaka/ukukhipha azisekelwe ku-Wear."</string>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d79ba63d..0f1a73f2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -274,4 +274,9 @@
before permissions can be changed. [CHAR LIMIT=NONE] -->
<string name="screen_overlay_button">Open settings</string>
+ <!-- Title of dialog telling users that Install/Uninstall action is not supported on Android Wear. -->
+ <string name="wear_not_allowed_dlg_title">Android Wear</string>
+ <!-- Title of dialog telling users that Install/Uninstall action is not supported on Android Wear. -->
+ <string name="wear_not_allowed_dlg_text">Instal/Uninstall actions not supported on Wear.</string>
+
</resources>
diff --git a/src/android/support/wearable/view/CircledImageView.java b/src/android/support/wearable/view/CircledImageView.java
new file mode 100644
index 00000000..53cb78cf
--- /dev/null
+++ b/src/android/support/wearable/view/CircledImageView.java
@@ -0,0 +1,603 @@
+/*
+ * Copyright (C) 2015 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 android.support.wearable.view;
+
+import android.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.RadialGradient;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.util.Objects;
+import com.android.packageinstaller.R;
+
+import com.android.packageinstaller.R;
+
+/**
+ * An image view surrounded by a circle.
+ */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class CircledImageView extends View {
+
+ private static final ArgbEvaluator ARGB_EVALUATOR = new ArgbEvaluator();
+
+ private Drawable mDrawable;
+
+ private final RectF mOval;
+ private final Paint mPaint;
+
+ private ColorStateList mCircleColor;
+
+ private float mCircleRadius;
+ private float mCircleRadiusPercent;
+
+ private float mCircleRadiusPressed;
+ private float mCircleRadiusPressedPercent;
+
+ private float mRadiusInset;
+
+ private int mCircleBorderColor;
+
+ private float mCircleBorderWidth;
+ private float mProgress = 1f;
+ private final float mShadowWidth;
+
+ private float mShadowVisibility;
+ private boolean mCircleHidden = false;
+
+ private float mInitialCircleRadius;
+
+ private boolean mPressed = false;
+
+ private boolean mProgressIndeterminate;
+ private ProgressDrawable mIndeterminateDrawable;
+ private Rect mIndeterminateBounds = new Rect();
+ private long mColorChangeAnimationDurationMs = 0;
+
+ private float mImageCirclePercentage = 1f;
+ private float mImageHorizontalOffcenterPercentage = 0f;
+ private Integer mImageTint;
+
+ private final Drawable.Callback mDrawableCallback = new Drawable.Callback() {
+ @Override
+ public void invalidateDrawable(Drawable drawable) {
+ invalidate();
+ }
+
+ @Override
+ public void scheduleDrawable(Drawable drawable, Runnable runnable, long l) {
+ // Not needed.
+ }
+
+ @Override
+ public void unscheduleDrawable(Drawable drawable, Runnable runnable) {
+ // Not needed.
+ }
+ };
+
+ private int mCurrentColor;
+
+ private final AnimatorUpdateListener mAnimationListener = new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ int color = (int) animation.getAnimatedValue();
+ if (color != CircledImageView.this.mCurrentColor) {
+ CircledImageView.this.mCurrentColor = color;
+ CircledImageView.this.invalidate();
+ }
+ }
+ };
+
+ private ValueAnimator mColorAnimator;
+
+ public CircledImageView(Context context) {
+ this(context, null);
+ }
+
+ public CircledImageView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public CircledImageView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CircledImageView);
+ mDrawable = a.getDrawable(R.styleable.CircledImageView_android_src);
+
+ mCircleColor = a.getColorStateList(R.styleable.CircledImageView_circle_color);
+ if (mCircleColor == null) {
+ mCircleColor = ColorStateList.valueOf(android.R.color.darker_gray);
+ }
+
+ mCircleRadius = a.getDimension(
+ R.styleable.CircledImageView_circle_radius, 0);
+ mInitialCircleRadius = mCircleRadius;
+ mCircleRadiusPressed = a.getDimension(
+ R.styleable.CircledImageView_circle_radius_pressed, mCircleRadius);
+ mCircleBorderColor = a.getColor(
+ R.styleable.CircledImageView_circle_border_color, Color.BLACK);
+ mCircleBorderWidth = a.getDimension(R.styleable.CircledImageView_circle_border_width, 0);
+
+ if (mCircleBorderWidth > 0) {
+ mRadiusInset += mCircleBorderWidth;
+ }
+
+ float circlePadding = a.getDimension(R.styleable.CircledImageView_circle_padding, 0);
+ if (circlePadding > 0) {
+ mRadiusInset += circlePadding;
+ }
+ mShadowWidth = a.getDimension(R.styleable.CircledImageView_shadow_width, 0);
+
+ mImageCirclePercentage = a.getFloat(
+ R.styleable.CircledImageView_image_circle_percentage, 0f);
+
+ mImageHorizontalOffcenterPercentage = a.getFloat(
+ R.styleable.CircledImageView_image_horizontal_offcenter_percentage, 0f);
+
+ if (a.hasValue(R.styleable.CircledImageView_image_tint)) {
+ mImageTint = a.getColor(R.styleable.CircledImageView_image_tint, 0);
+ }
+
+ mCircleRadiusPercent = a.getFraction(R.styleable.CircledImageView_circle_radius_percent,
+ 1, 1, 0f);
+
+ mCircleRadiusPressedPercent = a.getFraction(
+ R.styleable.CircledImageView_circle_radius_pressed_percent, 1, 1,
+ mCircleRadiusPercent);
+
+ a.recycle();
+
+ mOval = new RectF();
+ mPaint = new Paint();
+ mPaint.setAntiAlias(true);
+
+ mIndeterminateDrawable = new ProgressDrawable();
+ // {@link #mDrawableCallback} must be retained as a member, as Drawable callback
+ // is held by weak reference, we must retain it for it to continue to be called.
+ mIndeterminateDrawable.setCallback(mDrawableCallback);
+
+ setWillNotDraw(false);
+
+ setColorForCurrentState();
+ }
+
+ public void setCircleHidden(boolean circleHidden) {
+ if (circleHidden != mCircleHidden) {
+ mCircleHidden = circleHidden;
+ invalidate();
+ }
+ }
+
+
+ @Override
+ protected boolean onSetAlpha(int alpha) {
+ return true;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ int paddingLeft = getPaddingLeft();
+ int paddingTop = getPaddingTop();
+
+
+ float circleRadius = mPressed ? getCircleRadiusPressed() : getCircleRadius();
+ if (mShadowWidth > 0 && mShadowVisibility > 0) {
+ // First let's find the center of the view.
+ mOval.set(paddingLeft, paddingTop, getWidth() - getPaddingRight(),
+ getHeight() - getPaddingBottom());
+ // Having the center, lets make the shadow start beyond the circled and possibly the
+ // border.
+ final float radius = circleRadius + mCircleBorderWidth +
+ mShadowWidth * mShadowVisibility;
+ mPaint.setColor(Color.BLACK);
+ mPaint.setAlpha(Math.round(mPaint.getAlpha() * getAlpha()));
+ mPaint.setStyle(Style.FILL);
+ // TODO: precalc and pre-allocate this
+ mPaint.setShader(new RadialGradient(mOval.centerX(), mOval.centerY(), radius,
+ new int[]{Color.BLACK, Color.TRANSPARENT}, new float[]{0.6f, 1f},
+ Shader.TileMode.MIRROR));
+ canvas.drawCircle(mOval.centerX(), mOval.centerY(), radius, mPaint);
+ mPaint.setShader(null);
+ }
+ if (mCircleBorderWidth > 0) {
+ // First let's find the center of the view.
+ mOval.set(paddingLeft, paddingTop, getWidth() - getPaddingRight(),
+ getHeight() - getPaddingBottom());
+ // Having the center, lets make the border meet the circle.
+ mOval.set(mOval.centerX() - circleRadius, mOval.centerY() - circleRadius,
+ mOval.centerX() + circleRadius, mOval.centerY() + circleRadius);
+ mPaint.setColor(mCircleBorderColor);
+ // {@link #Paint.setAlpha} is a helper method that just sets the alpha portion of the
+ // color. {@link #Paint.setPaint} will clear any previously set alpha value.
+ mPaint.setAlpha(Math.round(mPaint.getAlpha() * getAlpha()));
+ mPaint.setStyle(Style.STROKE);
+ mPaint.setStrokeWidth(mCircleBorderWidth);
+
+ if (mProgressIndeterminate) {
+ mOval.roundOut(mIndeterminateBounds);
+ mIndeterminateDrawable.setBounds(mIndeterminateBounds);
+ mIndeterminateDrawable.setRingColor(mCircleBorderColor);
+ mIndeterminateDrawable.setRingWidth(mCircleBorderWidth);
+ mIndeterminateDrawable.draw(canvas);
+ } else {
+ canvas.drawArc(mOval, -90, 360 * mProgress, false, mPaint);
+ }
+ }
+ if (!mCircleHidden) {
+ mOval.set(paddingLeft, paddingTop, getWidth() - getPaddingRight(),
+ getHeight() - getPaddingBottom());
+ // {@link #Paint.setAlpha} is a helper method that just sets the alpha portion of the
+ // color. {@link #Paint.setPaint} will clear any previously set alpha value.
+ mPaint.setColor(mCurrentColor);
+ mPaint.setAlpha(Math.round(mPaint.getAlpha() * getAlpha()));
+
+ mPaint.setStyle(Style.FILL);
+ float centerX = mOval.centerX();
+ float centerY = mOval.centerY();
+
+ canvas.drawCircle(centerX, centerY, circleRadius, mPaint);
+ }
+
+ if (mDrawable != null) {
+ mDrawable.setAlpha(Math.round(getAlpha() * 255));
+
+ if (mImageTint != null) {
+ mDrawable.setTint(mImageTint);
+ }
+ mDrawable.draw(canvas);
+ }
+
+ super.onDraw(canvas);
+ }
+
+ private void setColorForCurrentState() {
+ int newColor = mCircleColor.getColorForState(getDrawableState(),
+ mCircleColor.getDefaultColor());
+ if (mColorChangeAnimationDurationMs > 0) {
+ if (mColorAnimator != null) {
+ mColorAnimator.cancel();
+ } else {
+ mColorAnimator = new ValueAnimator();
+ }
+ mColorAnimator.setIntValues(new int[] {
+ mCurrentColor, newColor });
+ mColorAnimator.setEvaluator(ARGB_EVALUATOR);
+ mColorAnimator.setDuration(mColorChangeAnimationDurationMs);
+ mColorAnimator.addUpdateListener(this.mAnimationListener);
+ mColorAnimator.start();
+ } else {
+ if (newColor != mCurrentColor) {
+ mCurrentColor = newColor;
+ invalidate();
+ }
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+
+ final float radius = getCircleRadius() + mCircleBorderWidth +
+ mShadowWidth * mShadowVisibility;
+ float desiredWidth = radius * 2;
+ float desiredHeight = radius * 2;
+
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+ int width;
+ int height;
+
+ if (widthMode == MeasureSpec.EXACTLY) {
+ width = widthSize;
+ } else if (widthMode == MeasureSpec.AT_MOST) {
+ width = (int) Math.min(desiredWidth, widthSize);
+ } else {
+ width = (int) desiredWidth;
+ }
+
+ if (heightMode == MeasureSpec.EXACTLY) {
+ height = heightSize;
+ } else if (heightMode == MeasureSpec.AT_MOST) {
+ height = (int) Math.min(desiredHeight, heightSize);
+ } else {
+ height = (int) desiredHeight;
+ }
+
+ super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (mDrawable != null) {
+ // Retrieve the sizes of the drawable and the view.
+ final int nativeDrawableWidth = mDrawable.getIntrinsicWidth();
+ final int nativeDrawableHeight = mDrawable.getIntrinsicHeight();
+ final int viewWidth = getMeasuredWidth();
+ final int viewHeight = getMeasuredHeight();
+ final float imageCirclePercentage = mImageCirclePercentage > 0
+ ? mImageCirclePercentage : 1;
+
+ final float scaleFactor = Math.min(1f,
+ Math.min(
+ (float) nativeDrawableWidth != 0
+ ? imageCirclePercentage * viewWidth / nativeDrawableWidth : 1,
+ (float) nativeDrawableHeight != 0
+ ? imageCirclePercentage
+ * viewHeight / nativeDrawableHeight : 1));
+
+ // Scale the drawable down to fit the view, if needed.
+ final int drawableWidth = Math.round(scaleFactor * nativeDrawableWidth);
+ final int drawableHeight = Math.round(scaleFactor * nativeDrawableHeight);
+
+ // Center the drawable within the view.
+ final int drawableLeft = (viewWidth - drawableWidth) / 2
+ + Math.round(mImageHorizontalOffcenterPercentage * drawableWidth);
+ final int drawableTop = (viewHeight - drawableHeight) / 2;
+
+ mDrawable.setBounds(drawableLeft, drawableTop, drawableLeft + drawableWidth,
+ drawableTop + drawableHeight);
+ }
+
+ super.onLayout(changed, left, top, right, bottom);
+ }
+
+ public void setImageDrawable(Drawable drawable) {
+ if (drawable != mDrawable) {
+ final Drawable existingDrawable = mDrawable;
+ mDrawable = drawable;
+
+ final boolean skipLayout = drawable != null
+ && existingDrawable != null
+ && existingDrawable.getIntrinsicHeight() == drawable.getIntrinsicHeight()
+ && existingDrawable.getIntrinsicWidth() == drawable.getIntrinsicWidth();
+
+ if (skipLayout) {
+ mDrawable.setBounds(existingDrawable.getBounds());
+ } else {
+ requestLayout();
+ }
+
+ invalidate();
+ }
+ }
+
+ public void setImageResource(int resId) {
+ setImageDrawable(resId == 0 ? null : getContext().getDrawable(resId));
+ }
+
+ public void setImageCirclePercentage(float percentage) {
+ float clamped = Math.max(0, Math.min(1, percentage));
+ if (clamped != mImageCirclePercentage) {
+ mImageCirclePercentage = clamped;
+ invalidate();
+ }
+ }
+
+ public void setImageHorizontalOffcenterPercentage(float percentage) {
+ if (percentage != mImageHorizontalOffcenterPercentage) {
+ mImageHorizontalOffcenterPercentage = percentage;
+ invalidate();
+ }
+ }
+
+ public void setImageTint(int tint) {
+ if (tint != mImageTint) {
+ mImageTint = tint;
+ invalidate();
+ }
+ }
+
+ public float getCircleRadius() {
+ float radius = mCircleRadius;
+ if (mCircleRadius <= 0 && mCircleRadiusPercent > 0) {
+ radius = Math.max(getMeasuredHeight(), getMeasuredWidth()) * mCircleRadiusPercent;
+ }
+
+ return radius - mRadiusInset;
+ }
+
+ public float getCircleRadiusPercent() {
+ return mCircleRadiusPercent;
+ }
+
+ public float getCircleRadiusPressed() {
+ float radius = mCircleRadiusPressed;
+
+ if (mCircleRadiusPressed <= 0 && mCircleRadiusPressedPercent > 0) {
+ radius = Math.max(getMeasuredHeight(), getMeasuredWidth())
+ * mCircleRadiusPressedPercent;
+ }
+
+ return radius - mRadiusInset;
+ }
+
+ public float getCircleRadiusPressedPercent() {
+ return mCircleRadiusPressedPercent;
+ }
+
+ public void setCircleRadius(float circleRadius) {
+ if (circleRadius != mCircleRadius) {
+ mCircleRadius = circleRadius;
+ invalidate();
+ }
+ }
+
+ /**
+ * Sets the radius of the circle to be a percentage of the largest dimension of the view.
+ * @param circleRadiusPercent A {@code float} from 0 to 1 representing the radius percentage.
+ */
+ public void setCircleRadiusPercent(float circleRadiusPercent) {
+ if (circleRadiusPercent != mCircleRadiusPercent) {
+ mCircleRadiusPercent = circleRadiusPercent;
+ invalidate();
+ }
+ }
+
+ public void setCircleRadiusPressed(float circleRadiusPressed) {
+ if (circleRadiusPressed != mCircleRadiusPressed) {
+ mCircleRadiusPressed = circleRadiusPressed;
+ invalidate();
+ }
+ }
+
+ /**
+ * Sets the radius of the circle to be a percentage of the largest dimension of the view when
+ * pressed.
+ * @param circleRadiusPressedPercent A {@code float} from 0 to 1 representing the radius
+ * percentage.
+ */
+ public void setCircleRadiusPressedPercent(float circleRadiusPressedPercent) {
+ if (circleRadiusPressedPercent != mCircleRadiusPressedPercent) {
+ mCircleRadiusPressedPercent = circleRadiusPressedPercent;
+ invalidate();
+ }
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+ setColorForCurrentState();
+ }
+
+ public void setCircleColor(int circleColor) {
+ setCircleColorStateList(ColorStateList.valueOf(circleColor));
+ }
+
+ public void setCircleColorStateList(ColorStateList circleColor) {
+ if (!Objects.equals(circleColor, mCircleColor)) {
+ mCircleColor = circleColor;
+ setColorForCurrentState();
+ invalidate();
+ }
+ }
+
+ public ColorStateList getCircleColorStateList() {
+ return mCircleColor;
+ }
+
+ public int getDefaultCircleColor() {
+ return mCircleColor.getDefaultColor();
+ }
+
+ /**
+ * Show the circle border as an indeterminate progress spinner.
+ * The views circle border width and color must be set for this to have an effect.
+ *
+ * @param show true if the progress spinner is shown, false to hide it.
+ */
+ public void showIndeterminateProgress(boolean show) {
+ mProgressIndeterminate = show;
+ if (show) {
+ mIndeterminateDrawable.startAnimation();
+ } else {
+ mIndeterminateDrawable.stopAnimation();
+ }
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ if (visibility != View.VISIBLE) {
+ showIndeterminateProgress(false);
+ } else if (mProgressIndeterminate) {
+ showIndeterminateProgress(true);
+ }
+ }
+
+ public void setProgress(float progress) {
+ if (progress != mProgress) {
+ mProgress = progress;
+ invalidate();
+ }
+ }
+
+ /**
+ * Set how much of the shadow should be shown.
+ * @param shadowVisibility Value between 0 and 1.
+ */
+ public void setShadowVisibility(float shadowVisibility) {
+ if (shadowVisibility != mShadowVisibility) {
+ mShadowVisibility = shadowVisibility;
+ invalidate();
+ }
+ }
+
+ public float getInitialCircleRadius() {
+ return mInitialCircleRadius;
+ }
+
+ public void setCircleBorderColor(int circleBorderColor) {
+ mCircleBorderColor = circleBorderColor;
+ }
+
+ /**
+ * Set the border around the circle.
+ * @param circleBorderWidth Width of the border around the circle.
+ */
+ public void setCircleBorderWidth(float circleBorderWidth) {
+ if (circleBorderWidth != mCircleBorderWidth) {
+ mCircleBorderWidth = circleBorderWidth;
+ invalidate();
+ }
+ }
+
+ @Override
+ public void setPressed(boolean pressed) {
+ super.setPressed(pressed);
+ if (pressed != mPressed) {
+ mPressed = pressed;
+ invalidate();
+ }
+ }
+
+ public Drawable getImageDrawable() {
+ return mDrawable;
+ }
+
+ /**
+ * @return the milliseconds duration of the transition animation when the color changes.
+ */
+ public long getColorChangeAnimationDuration() {
+ return mColorChangeAnimationDurationMs;
+ }
+
+ /**
+ * @param mColorChangeAnimationDurationMs the milliseconds duration of the color change
+ * animation. The color change animation will run if the color changes with {@link #setCircleColor}
+ * or as a result of the active state changing.
+ */
+ public void setColorChangeAnimationDuration(long mColorChangeAnimationDurationMs) {
+ this.mColorChangeAnimationDurationMs = mColorChangeAnimationDurationMs;
+ }
+}
diff --git a/src/android/support/wearable/view/Gusterpolator.java b/src/android/support/wearable/view/Gusterpolator.java
new file mode 100644
index 00000000..dc85bcb5
--- /dev/null
+++ b/src/android/support/wearable/view/Gusterpolator.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 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 android.support.wearable.view;
+
+import android.animation.TimeInterpolator;
+import android.annotation.TargetApi;
+import android.os.Build;
+
+/**
+ * Interpolator that uses a Bezier derived S shaped curve.
+ * @hide
+ */
+@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
+class Gusterpolator implements TimeInterpolator {
+
+ /** An instance of {@link android.support.wearable.view.Gusterpolator}. */
+ public static final Gusterpolator INSTANCE = new Gusterpolator();
+
+ /**
+ * To avoid users of this class creating multiple copies needlessly, the constructor is
+ * private.
+ */
+ private Gusterpolator() {}
+
+ /**
+ * Lookup table values.
+ * Generated using a Bezier curve from (0,0) to (1,1) with control points:
+ * P0 (0,0)
+ * P1 (0.4, 0)
+ * P2 (0.2, 1.0)
+ * P3 (1.0, 1.0)
+ *
+ * Values sampled with x at regular intervals between 0 and 1.
+ */
+ private static final float[] VALUES = new float[] {
+ 0.0f, 0.0002f, 0.0009f, 0.0019f, 0.0036f, 0.0059f, 0.0086f, 0.0119f, 0.0157f, 0.0209f,
+ 0.0257f, 0.0321f, 0.0392f, 0.0469f, 0.0566f, 0.0656f, 0.0768f, 0.0887f, 0.1033f, 0.1186f,
+ 0.1349f, 0.1519f, 0.1696f, 0.1928f, 0.2121f, 0.237f, 0.2627f, 0.2892f, 0.3109f, 0.3386f,
+ 0.3667f, 0.3952f, 0.4241f, 0.4474f, 0.4766f, 0.5f, 0.5234f, 0.5468f, 0.5701f, 0.5933f,
+ 0.6134f, 0.6333f, 0.6531f, 0.6698f, 0.6891f, 0.7054f, 0.7214f, 0.7346f, 0.7502f, 0.763f,
+ 0.7756f, 0.7879f, 0.8f, 0.8107f, 0.8212f, 0.8326f, 0.8415f, 0.8503f, 0.8588f, 0.8672f,
+ 0.8754f, 0.8833f, 0.8911f, 0.8977f, 0.9041f, 0.9113f, 0.9165f, 0.9232f, 0.9281f, 0.9328f,
+ 0.9382f, 0.9434f, 0.9476f, 0.9518f, 0.9557f, 0.9596f, 0.9632f, 0.9662f, 0.9695f, 0.9722f,
+ 0.9753f, 0.9777f, 0.9805f, 0.9826f, 0.9847f, 0.9866f, 0.9884f, 0.9901f, 0.9917f, 0.9931f,
+ 0.9944f, 0.9955f, 0.9964f, 0.9973f, 0.9981f, 0.9986f, 0.9992f, 0.9995f, 0.9998f, 1.0f, 1.0f
+ };
+
+ private static final float STEP_SIZE = 1.0f / (VALUES.length - 1);
+
+ @Override
+ public float getInterpolation(float input) {
+ if (input >= 1.0f) {
+ return 1.0f;
+ }
+
+ if (input <= 0f) {
+ return 0f;
+ }
+
+ int position = Math.min(
+ (int)(input * (VALUES.length - 1)),
+ VALUES.length - 2);
+
+ float quantized = position * STEP_SIZE;
+ float difference = input - quantized;
+ float weight = difference / STEP_SIZE;
+
+ return VALUES[position] + weight * (VALUES[position + 1] - VALUES[position]);
+ }
+}
diff --git a/src/android/support/wearable/view/ProgressDrawable.java b/src/android/support/wearable/view/ProgressDrawable.java
new file mode 100644
index 00000000..63e6a039
--- /dev/null
+++ b/src/android/support/wearable/view/ProgressDrawable.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2015 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 android.support.wearable.view;
+
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.util.Property;
+import android.view.animation.LinearInterpolator;
+
+/**
+ * Drawable for showing an indeterminate progress indicator.
+ *
+ * TODO: When Material progress drawable is available in the support library stop using this.
+ *
+ * @hide
+ */
+@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
+class ProgressDrawable extends Drawable {
+
+ private static Property<ProgressDrawable, Integer> LEVEL =
+ new Property<ProgressDrawable, Integer>(Integer.class, "level") {
+ @Override
+ public Integer get(ProgressDrawable drawable) {
+ return drawable.getLevel();
+ }
+
+ @Override
+ public void set(ProgressDrawable drawable, Integer value) {
+ drawable.setLevel(value);
+ drawable.invalidateSelf();
+ }
+ };
+ /** Max level for a level drawable, as specified in developer docs for {@link Drawable}. */
+ private static final int MAX_LEVEL = 10000;
+
+ /** How many different sections are there, five gives us the material style star. **/
+ private static final int NUMBER_OF_SEGMENTS = 5;
+
+ private static final int LEVELS_PER_SEGMENT = MAX_LEVEL / NUMBER_OF_SEGMENTS;
+ private static final float STARTING_ANGLE = -90f;
+ private static final long ANIMATION_DURATION = 6000;
+ private static final int FULL_CIRCLE = 360;
+ private static final int MAX_SWEEP = 306;
+ private static final int CORRECTION_ANGLE = FULL_CIRCLE - MAX_SWEEP;
+ /** How far through each cycle does the bar stop growing and start shrinking, half way. **/
+ private static final float GROW_SHRINK_RATIO = 0.5f;
+ // TODO: replace this with BakedBezierInterpolator when its available in support library.
+ private static final TimeInterpolator mInterpolator = Gusterpolator.INSTANCE;
+
+ private final RectF mInnerCircleBounds = new RectF();
+ private final Paint mPaint = new Paint();
+ private final ObjectAnimator mAnimator;
+ private float mCircleBorderWidth;
+ private int mCircleBorderColor;
+
+ public ProgressDrawable() {
+ mPaint.setAntiAlias(true);
+ mPaint.setStyle(Paint.Style.STROKE);
+ mAnimator = ObjectAnimator.ofInt(this, LEVEL, 0, MAX_LEVEL);
+ mAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ mAnimator.setRepeatMode(ValueAnimator.RESTART);
+ mAnimator.setDuration(ANIMATION_DURATION);
+ mAnimator.setInterpolator(new LinearInterpolator());
+ }
+
+ public void setRingColor(int color) {
+ mCircleBorderColor = color;
+ }
+
+ public void setRingWidth(float width) {
+ mCircleBorderWidth = width;
+ }
+
+ public void startAnimation() {
+ mAnimator.start();
+ }
+
+ public void stopAnimation() {
+ mAnimator.cancel();
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ canvas.save();
+ mInnerCircleBounds.set(getBounds());
+ mInnerCircleBounds.inset(mCircleBorderWidth / 2.0f, mCircleBorderWidth / 2.0f);
+ mPaint.setStrokeWidth(mCircleBorderWidth);
+ mPaint.setColor(mCircleBorderColor);
+
+ float sweepAngle = FULL_CIRCLE;
+ boolean growing = false;
+ float correctionAngle = 0;
+ int level = getLevel();
+
+ int currentSegment = level / LEVELS_PER_SEGMENT;
+ int offset = currentSegment * LEVELS_PER_SEGMENT;
+ float progress = (level - offset) / (float) LEVELS_PER_SEGMENT;
+
+ growing = progress < GROW_SHRINK_RATIO;
+ correctionAngle = CORRECTION_ANGLE * progress;
+
+ if (growing) {
+ sweepAngle = MAX_SWEEP * mInterpolator.getInterpolation(
+ lerpInv(0f, GROW_SHRINK_RATIO, progress));
+ } else {
+ sweepAngle = MAX_SWEEP * (1.0f - mInterpolator.getInterpolation(
+ lerpInv(GROW_SHRINK_RATIO, 1.0f, progress)));
+ }
+
+ sweepAngle = Math.max(1, sweepAngle);
+
+ canvas.rotate(
+ level * (1.0f / MAX_LEVEL) * 2 * FULL_CIRCLE + STARTING_ANGLE + correctionAngle,
+ mInnerCircleBounds.centerX(),
+ mInnerCircleBounds.centerY());
+ canvas.drawArc(mInnerCircleBounds,
+ growing ? 0 : MAX_SWEEP - sweepAngle,
+ sweepAngle,
+ false,
+ mPaint);
+ canvas.restore();
+ }
+
+ @Override
+ public void setAlpha(int i) {
+ // Not supported.
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ // Not supported.
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.OPAQUE;
+ }
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ return true; // Changing the level of this drawable does change its appearance.
+ }
+
+ /**
+ * Returns the interpolation scalar (s) that satisfies the equation:
+ * {@code value = }lerp(a, b, s)
+ *
+ * <p>If {@code a == b}, then this function will return 0.
+ */
+ private static float lerpInv(float a, float b, float value) {
+ return a != b ? ((value - a) / (b - a)) : 0.0f;
+ }
+}
diff --git a/src/android/support/wearable/view/SimpleAnimatorListener.java b/src/android/support/wearable/view/SimpleAnimatorListener.java
new file mode 100644
index 00000000..13631a2a
--- /dev/null
+++ b/src/android/support/wearable/view/SimpleAnimatorListener.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 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 android.support.wearable.view;
+
+import android.animation.Animator;
+import android.annotation.TargetApi;
+import android.os.Build;
+
+/**
+ * Convenience class for listening for Animator events that implements the AnimatorListener
+ * interface and allows extending only methods that are necessary.
+ */
+@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
+public class SimpleAnimatorListener implements Animator.AnimatorListener {
+
+ private boolean mWasCanceled;
+
+ @Override
+ public void onAnimationCancel(Animator animator) {
+ mWasCanceled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ if (!mWasCanceled) {
+ onAnimationComplete(animator);
+ }
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animator) {
+ }
+
+ @Override
+ public void onAnimationStart(Animator animator) {
+ mWasCanceled = false;
+ }
+
+ /**
+ * Called when the animation finishes. Not called if the animation was canceled.
+ */
+ public void onAnimationComplete(Animator animator) {
+ }
+
+ /**
+ * Provides information if the animation was cancelled.
+ * @return True if animation was cancelled.
+ */
+ public boolean wasCanceled() {
+ return mWasCanceled;
+ }
+
+}
diff --git a/src/android/support/wearable/view/WearableListView.java b/src/android/support/wearable/view/WearableListView.java
new file mode 100644
index 00000000..01baa98b
--- /dev/null
+++ b/src/android/support/wearable/view/WearableListView.java
@@ -0,0 +1,1387 @@
+/*
+ * Copyright (C) 2015 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 android.support.wearable.view;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.PointF;
+import android.os.Build;
+import android.os.Handler;
+import android.support.v7.widget.LinearSmoothScroller;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.Property;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.widget.Scroller;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An alternative version of ListView that is optimized for ease of use on small screen wearable
+ * devices. It displays a vertically scrollable list of items, and automatically snaps to the
+ * nearest item when the user stops scrolling.
+ *
+ * <p>
+ * For a quick start, you will need to implement a subclass of {@link .Adapter},
+ * which will create and bind your views to the {@link .ViewHolder} objects. If you want to add
+ * more visual treatment to your views when they become the central items of the
+ * WearableListView, have them implement the {@link .OnCenterProximityListener} interface.
+ * </p>
+ */
+@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
+public class WearableListView extends RecyclerView {
+ @SuppressWarnings("unused")
+ private static final String TAG = "WearableListView";
+
+ private static final long FLIP_ANIMATION_DURATION_MS = 150;
+ private static final long CENTERING_ANIMATION_DURATION_MS = 150;
+
+ private static final float TOP_TAP_REGION_PERCENTAGE = .33f;
+ private static final float BOTTOM_TAP_REGION_PERCENTAGE = .33f;
+
+ // Each item will occupy one third of the height.
+ private static final int THIRD = 3;
+
+ private final int mMinFlingVelocity;
+ private final int mMaxFlingVelocity;
+
+ private boolean mMaximizeSingleItem;
+ private boolean mCanClick = true;
+ // WristGesture navigation signals are delivered as KeyEvents. Allow developer to disable them
+ // for this specific View. It might be cleaner to simply have users re-implement onKeyDown().
+ // TOOD: Finalize the disabling mechanism here.
+ private boolean mGestureNavigationEnabled = true;
+ private int mTapPositionX;
+ private int mTapPositionY;
+ private ClickListener mClickListener;
+
+ private Animator mScrollAnimator;
+ // This is a little hacky due to the fact that animator provides incremental values instead of
+ // deltas and scrolling code requires deltas. We animate WearableListView directly and use this
+ // field to calculate deltas. Obviously this means that only one scrolling algorithm can run at
+ // a time, but I don't think it would be wise to have more than one running.
+ private int mLastScrollChange;
+
+ private SetScrollVerticallyProperty mSetScrollVerticallyProperty =
+ new SetScrollVerticallyProperty();
+
+ private final List<OnScrollListener> mOnScrollListeners = new ArrayList<OnScrollListener>();
+
+ private final List<OnCentralPositionChangedListener> mOnCentralPositionChangedListeners =
+ new ArrayList<OnCentralPositionChangedListener>();
+
+ private OnOverScrollListener mOverScrollListener;
+
+ private boolean mGreedyTouchMode;
+
+ private float mStartX;
+
+ private float mStartY;
+
+ private float mStartFirstTop;
+
+ private final int mTouchSlop;
+
+ private boolean mPossibleVerticalSwipe;
+
+ private int mInitialOffset = 0;
+
+ private Scroller mScroller;
+
+ // Top and bottom boundaries for tap checking. Need to recompute by calling computeTapRegions
+ // before referencing.
+ private final float[] mTapRegions = new float[2];
+
+ private boolean mGestureDirectionLocked;
+ private int mPreviousCentral = 0;
+
+ // Temp variable for storing locations on screen.
+ private final int[] mLocation = new int[2];
+
+ // TODO: Consider clearing this when underlying data set changes. If the data set changes, you
+ // can't safely assume that this pressed view is in the same place as it was before and it will
+ // receive setPressed(false) unnecessarily. In theory it should be fine, but in practice we
+ // have places like this: mIconView.setCircleColor(pressed ? mPressedColor : mSelectedColor);
+ // This might set selected color on non selected item. Our logic should be: if you change
+ // underlying data set, all best are off and you need to preserve the state; we will clear
+ // this field. However, I am not willing to introduce this so late in C development.
+ private View mPressedView = null;
+
+ private final Runnable mPressedRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (getChildCount() > 0) {
+ mPressedView = getChildAt(findCenterViewIndex());
+ mPressedView.setPressed(true);
+ } else {
+ Log.w(TAG, "mPressedRunnable: the children were removed, skipping.");
+ }
+ }
+ };
+
+ private final Runnable mReleasedRunnable = new Runnable() {
+ @Override
+ public void run() {
+ releasePressedItem();
+ }
+ };
+
+ private Runnable mNotifyChildrenPostLayoutRunnable = new Runnable() {
+ @Override
+ public void run() {
+ notifyChildrenAboutProximity(false);
+ }
+ };
+
+ private final AdapterDataObserver mObserver = new AdapterDataObserver() {
+ @Override
+ public void onChanged() {
+ WearableListView.this.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ WearableListView.this.removeOnLayoutChangeListener(this);
+ if (WearableListView.this.getChildCount() > 0) {
+ WearableListView.this.animateToCenter();
+ }
+ }
+ });
+ }
+ };
+
+ public WearableListView(Context context) {
+ this(context, null);
+ }
+
+ public WearableListView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public WearableListView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setHasFixedSize(true);
+ setOverScrollMode(View.OVER_SCROLL_NEVER);
+ setLayoutManager(new LayoutManager());
+
+ final RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+ if (newState == RecyclerView.SCROLL_STATE_IDLE && getChildCount() > 0) {
+ handleTouchUp(null, newState);
+ }
+ for (OnScrollListener listener : mOnScrollListeners) {
+ listener.onScrollStateChanged(newState);
+ }
+ }
+
+ @Override
+ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+ onScroll(dy);
+ }
+ };
+ setOnScrollListener(onScrollListener);
+
+ final ViewConfiguration vc = ViewConfiguration.get(context);
+ mTouchSlop = vc.getScaledTouchSlop();
+
+ mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
+ mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
+ }
+
+ @Override
+ public void setAdapter(RecyclerView.Adapter adapter) {
+ RecyclerView.Adapter currentAdapter = getAdapter();
+ if (currentAdapter != null) {
+ currentAdapter.unregisterAdapterDataObserver(mObserver);
+ }
+
+ super.setAdapter(adapter);
+
+ if (adapter != null) {
+ adapter.registerAdapterDataObserver(mObserver);
+ }
+ }
+
+ /**
+ * @return the position of the center child's baseline; -1 if no center child exists or if
+ * the center child does not return a valid baseline.
+ */
+ @Override
+ public int getBaseline() {
+ // No children implies there is no center child for which a baseline can be computed.
+ if (getChildCount() == 0) {
+ return super.getBaseline();
+ }
+
+ // Compute the baseline of the center child.
+ final int centerChildIndex = findCenterViewIndex();
+ final int centerChildBaseline = getChildAt(centerChildIndex).getBaseline();
+
+ // If the center child has no baseline, neither does this list view.
+ if (centerChildBaseline == -1) {
+ return super.getBaseline();
+ }
+
+ return getCentralViewTop() + centerChildBaseline;
+ }
+
+ /**
+ * @return true if the list is scrolled all the way to the top.
+ */
+ public boolean isAtTop() {
+ if (getChildCount() == 0) {
+ return true;
+ }
+
+ int centerChildIndex = findCenterViewIndex();
+ View centerView = getChildAt(centerChildIndex);
+ return getChildAdapterPosition(centerView) == 0 &&
+ getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
+ }
+
+ /**
+ * Clears the state of the layout manager that positions list items.
+ */
+ public void resetLayoutManager() {
+ setLayoutManager(new LayoutManager());
+ }
+
+ /**
+ * Controls whether WearableListView should intercept all touch events and also prevent the
+ * parent from receiving them.
+ * @param greedy If true it will intercept all touch events.
+ */
+ public void setGreedyTouchMode(boolean greedy) {
+ mGreedyTouchMode = greedy;
+ }
+
+ /**
+ * By default the first element of the list is initially positioned in the center of the screen.
+ * This method allows the developer to specify a different offset, e.g. to hide the
+ * WearableListView before the user is allowed to use it.
+ *
+ * @param top How far the elements should be pushed down.
+ */
+ public void setInitialOffset(int top) {
+ mInitialOffset = top;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+ if (!isEnabled()) {
+ return false;
+ }
+
+ if (mGreedyTouchMode && getChildCount() > 0) {
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_DOWN) {
+ mStartX = event.getX();
+ mStartY = event.getY();
+ mStartFirstTop = getChildCount() > 0 ? getChildAt(0).getTop() : 0;
+ mPossibleVerticalSwipe = true;
+ mGestureDirectionLocked = false;
+ } else if (action == MotionEvent.ACTION_MOVE && mPossibleVerticalSwipe) {
+ handlePossibleVerticalSwipe(event);
+ }
+ getParent().requestDisallowInterceptTouchEvent(mPossibleVerticalSwipe);
+ }
+ return super.onInterceptTouchEvent(event);
+ }
+
+ private boolean handlePossibleVerticalSwipe(MotionEvent event) {
+ if (mGestureDirectionLocked) {
+ return mPossibleVerticalSwipe;
+ }
+ float deltaX = Math.abs(mStartX - event.getX());
+ float deltaY = Math.abs(mStartY - event.getY());
+ float distance = (deltaX * deltaX) + (deltaY * deltaY);
+ // Verify that the distance moved in the combined x/y direction is at
+ // least touch slop before determining the gesture direction.
+ if (distance > (mTouchSlop * mTouchSlop)) {
+ if (deltaX > deltaY) {
+ mPossibleVerticalSwipe = false;
+ }
+ mGestureDirectionLocked = true;
+ }
+ return mPossibleVerticalSwipe;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (!isEnabled()) {
+ return false;
+ }
+
+ // super.onTouchEvent can change the state of the scroll, keep a copy so that handleTouchUp
+ // can exit early if scrollState != IDLE when the touch event started.
+ int scrollState = getScrollState();
+ boolean result = super.onTouchEvent(event);
+ if (getChildCount() > 0) {
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_DOWN) {
+ handleTouchDown(event);
+ } else if (action == MotionEvent.ACTION_UP) {
+ handleTouchUp(event, scrollState);
+ getParent().requestDisallowInterceptTouchEvent(false);
+ } else if (action == MotionEvent.ACTION_MOVE) {
+ if (Math.abs(mTapPositionX - (int) event.getX()) >= mTouchSlop ||
+ Math.abs(mTapPositionY - (int) event.getY()) >= mTouchSlop) {
+ releasePressedItem();
+ mCanClick = false;
+ }
+ result |= handlePossibleVerticalSwipe(event);
+ getParent().requestDisallowInterceptTouchEvent(mPossibleVerticalSwipe);
+ } else if (action == MotionEvent.ACTION_CANCEL) {
+ getParent().requestDisallowInterceptTouchEvent(false);
+ mCanClick = true;
+ }
+ }
+ return result;
+ }
+
+ private void releasePressedItem() {
+ if (mPressedView != null) {
+ mPressedView.setPressed(false);
+ mPressedView = null;
+ }
+ Handler handler = getHandler();
+ if (handler != null) {
+ handler.removeCallbacks(mPressedRunnable);
+ }
+ }
+
+ private void onScroll(int dy) {
+ for (OnScrollListener listener : mOnScrollListeners) {
+ listener.onScroll(dy);
+ }
+ notifyChildrenAboutProximity(true);
+ }
+
+ /**
+ * Adds a listener that will be called when the content of the list view is scrolled.
+ */
+ public void addOnScrollListener(OnScrollListener listener) {
+ mOnScrollListeners.add(listener);
+ }
+
+ /**
+ * Removes listener for scroll events.
+ */
+ public void removeOnScrollListener(OnScrollListener listener) {
+ mOnScrollListeners.remove(listener);
+ }
+
+ /**
+ * Adds a listener that will be called when the central item of the list changes.
+ */
+ public void addOnCentralPositionChangedListener(OnCentralPositionChangedListener listener) {
+ mOnCentralPositionChangedListeners.add(listener);
+ }
+
+ /**
+ * Removes a listener that would be called when the central item of the list changes.
+ */
+ public void removeOnCentralPositionChangedListener(OnCentralPositionChangedListener listener) {
+ mOnCentralPositionChangedListeners.remove(listener);
+ }
+
+ /**
+ * Determines if navigation of list with wrist gestures is enabled.
+ */
+ public boolean isGestureNavigationEnabled() {
+ return mGestureNavigationEnabled;
+ }
+
+ /**
+ * Sets whether navigation of list with wrist gestures is enabled.
+ */
+ public void setEnableGestureNavigation(boolean enabled) {
+ mGestureNavigationEnabled = enabled;
+ }
+
+ @Override /* KeyEvent.Callback */
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ // Respond to keycodes (at least originally generated and injected by wrist gestures).
+ if (mGestureNavigationEnabled) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_NAVIGATE_PREVIOUS:
+ fling(0, -mMinFlingVelocity);
+ return true;
+ case KeyEvent.KEYCODE_NAVIGATE_NEXT:
+ fling(0, mMinFlingVelocity);
+ return true;
+ case KeyEvent.KEYCODE_NAVIGATE_IN:
+ return tapCenterView();
+ case KeyEvent.KEYCODE_NAVIGATE_OUT:
+ // Returing false leaves the action to the container of this WearableListView
+ // (e.g. finishing the activity containing this WearableListView).
+ return false;
+ }
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ /**
+ * Simulate tapping the child view at the center of this list.
+ */
+ private boolean tapCenterView() {
+ if (!isEnabled() || getVisibility() != View.VISIBLE) {
+ return false;
+ }
+ int index = findCenterViewIndex();
+ View view = getChildAt(index);
+ ViewHolder holder = getChildViewHolder(view);
+ if (mClickListener != null) {
+ mClickListener.onClick(holder);
+ return true;
+ }
+ return false;
+ }
+
+ private boolean checkForTap(MotionEvent event) {
+ // No taps are accepted if this view is disabled.
+ if (!isEnabled()) {
+ return false;
+ }
+
+ float rawY = event.getRawY();
+ int index = findCenterViewIndex();
+ View view = getChildAt(index);
+ ViewHolder holder = getChildViewHolder(view);
+ computeTapRegions(mTapRegions);
+ if (rawY > mTapRegions[0] && rawY < mTapRegions[1]) {
+ if (mClickListener != null) {
+ mClickListener.onClick(holder);
+ }
+ return true;
+ }
+ if (index > 0 && rawY <= mTapRegions[0]) {
+ animateToMiddle(index - 1, index);
+ return true;
+ }
+ if (index < getChildCount() - 1 && rawY >= mTapRegions[1]) {
+ animateToMiddle(index + 1, index);
+ return true;
+ }
+ if (index == 0 && rawY <= mTapRegions[0] && mClickListener != null) {
+ // Special case: if the top third of the screen is empty and the touch event happens
+ // there, we don't want to immediately disallow the parent from using it. We tell
+ // parent to disallow intercept only after we locked a gesture. Before that he
+ // might do something with the action.
+ mClickListener.onTopEmptyRegionClick();
+ return true;
+ }
+ return false;
+ }
+
+ private void animateToMiddle(int newCenterIndex, int oldCenterIndex) {
+ if (newCenterIndex == oldCenterIndex) {
+ throw new IllegalArgumentException(
+ "newCenterIndex must be different from oldCenterIndex");
+ }
+ List<Animator> animators = new ArrayList<Animator>();
+ View child = getChildAt(newCenterIndex);
+ int scrollToMiddle = getCentralViewTop() - child.getTop();
+ startScrollAnimation(animators, scrollToMiddle, FLIP_ANIMATION_DURATION_MS);
+ }
+
+ private void startScrollAnimation(List<Animator> animators, int scroll, long duration) {
+ startScrollAnimation(animators, scroll, duration, 0);
+ }
+
+ private void startScrollAnimation(List<Animator> animators, int scroll, long duration,
+ long delay) {
+ startScrollAnimation(animators, scroll, duration, delay, null);
+ }
+
+ private void startScrollAnimation(
+ int scroll, long duration, long delay, Animator.AnimatorListener listener) {
+ startScrollAnimation(null, scroll, duration, delay, listener);
+ }
+
+ private void startScrollAnimation(List<Animator> animators, int scroll, long duration,
+ long delay, Animator.AnimatorListener listener) {
+ if (mScrollAnimator != null) {
+ mScrollAnimator.cancel();
+ }
+
+ mLastScrollChange = 0;
+ ObjectAnimator scrollAnimator = ObjectAnimator.ofInt(this, mSetScrollVerticallyProperty,
+ 0, -scroll);
+
+ if (animators != null) {
+ animators.add(scrollAnimator);
+ AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.playTogether(animators);
+ mScrollAnimator = animatorSet;
+ } else {
+ mScrollAnimator = scrollAnimator;
+ }
+ mScrollAnimator.setDuration(duration);
+ if (listener != null) {
+ mScrollAnimator.addListener(listener);
+ }
+ if (delay > 0) {
+ mScrollAnimator.setStartDelay(delay);
+ }
+ mScrollAnimator.start();
+ }
+
+ @Override
+ public boolean fling(int velocityX, int velocityY) {
+ if (getChildCount() == 0) {
+ return false;
+ }
+ // If we are flinging towards empty space (before first element or after last), we reuse
+ // original flinging mechanism.
+ final int index = findCenterViewIndex();
+ final View child = getChildAt(index);
+ int currentPosition = getChildPosition(child);
+ if ((currentPosition == 0 && velocityY < 0) ||
+ (currentPosition == getAdapter().getItemCount() - 1 && velocityY > 0)) {
+ return super.fling(velocityX, velocityY);
+ }
+
+ if (Math.abs(velocityY) < mMinFlingVelocity) {
+ return false;
+ }
+ velocityY = Math.max(Math.min(velocityY, mMaxFlingVelocity), -mMaxFlingVelocity);
+
+ if (mScroller == null) {
+ mScroller = new Scroller(getContext(), null, true);
+ }
+ mScroller.fling(0, 0, 0, velocityY, Integer.MIN_VALUE, Integer.MAX_VALUE,
+ Integer.MIN_VALUE, Integer.MAX_VALUE);
+ int finalY = mScroller.getFinalY();
+ int delta = finalY / (getPaddingTop() + getAdjustedHeight() / 2);
+ if (delta == 0) {
+ // If the fling would not be enough to change position, we increase it to satisfy user's
+ // intent of switching current position.
+ delta = velocityY > 0 ? 1 : -1;
+ }
+ int finalPosition = Math.max(
+ 0, Math.min(getAdapter().getItemCount() - 1, currentPosition + delta));
+ smoothScrollToPosition(finalPosition);
+ return true;
+ }
+
+ public void smoothScrollToPosition(int position, RecyclerView.SmoothScroller smoothScroller) {
+ LayoutManager layoutManager = (LayoutManager) getLayoutManager();
+ layoutManager.setCustomSmoothScroller(smoothScroller);
+ smoothScrollToPosition(position);
+ layoutManager.clearCustomSmoothScroller();
+ }
+
+ @Override
+ public ViewHolder getChildViewHolder(View child) {
+ return (ViewHolder) super.getChildViewHolder(child);
+ }
+
+ /**
+ * Adds a listener that will be called when the user taps on the WearableListView or its items.
+ */
+ public void setClickListener(ClickListener clickListener) {
+ mClickListener = clickListener;
+ }
+
+ /**
+ * Adds a listener that will be called when the user drags the top element below its allowed
+ * bottom position.
+ *
+ * @hide
+ */
+ public void setOverScrollListener(OnOverScrollListener listener) {
+ mOverScrollListener = listener;
+ }
+
+ private int findCenterViewIndex() {
+ // TODO(gruszczy): This could be easily optimized, so that we stop looking when we the
+ // distance starts growing again, instead of finding the closest. It would safe half of
+ // the loop.
+ int count = getChildCount();
+ int index = -1;
+ int closest = Integer.MAX_VALUE;
+ int centerY = getCenterYPos(this);
+ for (int i = 0; i < count; ++i) {
+ final View child = getChildAt(i);
+ int childCenterY = getTop() + getCenterYPos(child);
+ final int distance = Math.abs(centerY - childCenterY);
+ if (distance < closest) {
+ closest = distance;
+ index = i;
+ }
+ }
+ if (index == -1) {
+ throw new IllegalStateException("Can't find central view.");
+ }
+ return index;
+ }
+
+ private static int getCenterYPos(View v) {
+ return v.getTop() + v.getPaddingTop() + getAdjustedHeight(v) / 2;
+ }
+
+ private void handleTouchUp(MotionEvent event, int scrollState) {
+ if (mCanClick && event != null && checkForTap(event)) {
+ Handler handler = getHandler();
+ if (handler != null) {
+ handler.postDelayed(mReleasedRunnable, ViewConfiguration.getTapTimeout());
+ }
+ return;
+ }
+
+ if (scrollState != RecyclerView.SCROLL_STATE_IDLE) {
+ // We are flinging, so let's not start animations just yet. Instead we will start them
+ // when the fling finishes.
+ return;
+ }
+
+ if (isOverScrolling()) {
+ mOverScrollListener.onOverScroll();
+ } else {
+ animateToCenter();
+ }
+ }
+
+ private boolean isOverScrolling() {
+ return getChildCount() > 0
+ // If first view top was below the central top, it means it was never centered.
+ // Don't allow overscroll, otherwise a simple touch (instead of a drag) will be
+ // enough to trigger overscroll.
+ && mStartFirstTop <= getCentralViewTop()
+ && getChildAt(0).getTop() >= getTopViewMaxTop()
+ && mOverScrollListener != null;
+ }
+
+ private int getTopViewMaxTop() {
+ return getHeight() / 2;
+ }
+
+ private int getItemHeight() {
+ // Round up so that the screen is fully occupied by 3 items.
+ return getAdjustedHeight() / THIRD + 1;
+ }
+
+ /**
+ * Returns top of the central {@code View} in the list when such view is fully centered.
+ *
+ * This is a more or a less a static value that you can use to align other views with the
+ * central one.
+ */
+ public int getCentralViewTop() {
+ return getPaddingTop() + getItemHeight();
+ }
+
+ /**
+ * Automatically starts an animation that snaps the list to center on the element closest to the
+ * middle.
+ */
+ public void animateToCenter() {
+ final int index = findCenterViewIndex();
+ final View child = getChildAt(index);
+ final int scrollToMiddle = getCentralViewTop() - child.getTop();
+ startScrollAnimation(scrollToMiddle, CENTERING_ANIMATION_DURATION_MS, 0,
+ new SimpleAnimatorListener() {
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ if (!wasCanceled()) {
+ mCanClick = true;
+ }
+ }
+ });
+ }
+
+ /**
+ * Animate the list so that the first view is back to its initial position.
+ * @param endAction Action to execute when the animation is done.
+ * @hide
+ */
+ public void animateToInitialPosition(final Runnable endAction) {
+ final View child = getChildAt(0);
+ final int scrollToMiddle = getCentralViewTop() + mInitialOffset - child.getTop();
+ startScrollAnimation(scrollToMiddle, CENTERING_ANIMATION_DURATION_MS, 0,
+ new SimpleAnimatorListener() {
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ if (endAction != null) {
+ endAction.run();
+ }
+ }
+ });
+ }
+
+ private void handleTouchDown(MotionEvent event) {
+ if (mCanClick) {
+ mTapPositionX = (int) event.getX();
+ mTapPositionY = (int) event.getY();
+ float rawY = event.getRawY();
+ computeTapRegions(mTapRegions);
+ if (rawY > mTapRegions[0] && rawY < mTapRegions[1]) {
+ View view = getChildAt(findCenterViewIndex());
+ if (view instanceof OnCenterProximityListener) {
+ Handler handler = getHandler();
+ if (handler != null) {
+ handler.removeCallbacks(mReleasedRunnable);
+ handler.postDelayed(mPressedRunnable, ViewConfiguration.getTapTimeout());
+ }
+ }
+ }
+ }
+ }
+
+ private void setScrollVertically(int scroll) {
+ scrollBy(0, scroll - mLastScrollChange);
+ mLastScrollChange = scroll;
+ }
+
+ private int getAdjustedHeight() {
+ return getAdjustedHeight(this);
+ }
+
+ private static int getAdjustedHeight(View v) {
+ return v.getHeight() - v.getPaddingBottom() - v.getPaddingTop();
+ }
+
+ private void computeTapRegions(float[] tapRegions) {
+ mLocation[0] = mLocation[1] = 0;
+ getLocationOnScreen(mLocation);
+ int mScreenTop = mLocation[1];
+ int height = getHeight();
+ tapRegions[0] = mScreenTop + height * TOP_TAP_REGION_PERCENTAGE;
+ tapRegions[1] = mScreenTop + height * (1 - BOTTOM_TAP_REGION_PERCENTAGE);
+ }
+
+ /**
+ * Determines if, when there is only one item in the WearableListView, that the single item
+ * is laid out so that it's height fills the entire WearableListView.
+ */
+ public boolean getMaximizeSingleItem() {
+ return mMaximizeSingleItem;
+ }
+
+ /**
+ * When set to true, if there is only one item in the WearableListView, it will fill the entire
+ * WearableListView. When set to false, the default behavior will be used and the single item
+ * will fill only a third of the screen.
+ */
+ public void setMaximizeSingleItem(boolean maximizeSingleItem) {
+ mMaximizeSingleItem = maximizeSingleItem;
+ }
+
+ private void notifyChildrenAboutProximity(boolean animate) {
+ LayoutManager layoutManager = (LayoutManager) getLayoutManager();
+ int count = layoutManager.getChildCount();
+
+ if (count == 0) {
+ return;
+ }
+
+ int index = layoutManager.findCenterViewIndex();
+ for (int i = 0; i < count; ++i) {
+ final View view = layoutManager.getChildAt(i);
+ ViewHolder holder = getChildViewHolder(view);
+ holder.onCenterProximity(i == index, animate);
+ }
+ final int position = getChildViewHolder(getChildAt(index)).getPosition();
+ if (position != mPreviousCentral) {
+ for (OnScrollListener listener : mOnScrollListeners) {
+ listener.onCentralPositionChanged(position);
+ }
+ for (OnCentralPositionChangedListener listener :
+ mOnCentralPositionChangedListeners) {
+ listener.onCentralPositionChanged(position);
+ }
+ mPreviousCentral = position;
+ }
+ }
+
+ // TODO: Move this to a separate class, so it can't directly interact with the WearableListView.
+ private class LayoutManager extends RecyclerView.LayoutManager {
+ private int mFirstPosition;
+
+ private boolean mPushFirstHigher;
+
+ private int mAbsoluteScroll;
+
+ private boolean mUseOldViewTop = true;
+
+ private boolean mWasZoomedIn = false;
+
+ private RecyclerView.SmoothScroller mSmoothScroller;
+
+ private RecyclerView.SmoothScroller mDefaultSmoothScroller;
+
+ // We need to have another copy of the same method, because this one uses
+ // LayoutManager.getChildCount/getChildAt instead of View.getChildCount/getChildAt and
+ // they return different values.
+ private int findCenterViewIndex() {
+ // TODO(gruszczy): This could be easily optimized, so that we stop looking when we the
+ // distance starts growing again, instead of finding the closest. It would safe half of
+ // the loop.
+ int count = getChildCount();
+ int index = -1;
+ int closest = Integer.MAX_VALUE;
+ int centerY = getCenterYPos(WearableListView.this);
+ for (int i = 0; i < count; ++i) {
+ final View child = getLayoutManager().getChildAt(i);
+ int childCenterY = getTop() + getCenterYPos(child);
+ final int distance = Math.abs(centerY - childCenterY);
+ if (distance < closest) {
+ closest = distance;
+ index = i;
+ }
+ }
+ if (index == -1) {
+ throw new IllegalStateException("Can't find central view.");
+ }
+ return index;
+ }
+
+ @Override
+ public void onLayoutChildren(RecyclerView.Recycler recycler, State state) {
+ final int parentBottom = getHeight() - getPaddingBottom();
+ // By default we assume this is the first run and the first element will be centered
+ // with optional initial offset.
+ int oldTop = getCentralViewTop() + mInitialOffset;
+ // Here we handle any other situation where we relayout or we want to achieve a
+ // specific layout of children.
+ if (mUseOldViewTop && getChildCount() > 0) {
+ // We are performing a relayout after we already had some children, because e.g. the
+ // contents of an adapter has changed. First we want to check, if the central item
+ // from before the layout is still here, because we want to preserve it.
+ int index = findCenterViewIndex();
+ int position = getPosition(getChildAt(index));
+ if (position == NO_POSITION) {
+ // Central item was removed. Let's find the first surviving item and use it
+ // as an anchor.
+ for (int i = 0, N = getChildCount(); index + i < N || index - i >= 0; ++i) {
+ View child = getChildAt(index + i);
+ if (child != null) {
+ position = getPosition(child);
+ if (position != NO_POSITION) {
+ index = index + i;
+ break;
+ }
+ }
+ child = getChildAt(index - i);
+ if (child != null) {
+ position = getPosition(child);
+ if (position != NO_POSITION) {
+ index = index - i;
+ break;
+ }
+ }
+ }
+ }
+ if (position == NO_POSITION) {
+ // None of the children survives the relayout, let's just use the top of the
+ // first one.
+ oldTop = getChildAt(0).getTop();
+ int count = state.getItemCount();
+ // Lets first make sure that the first position is not above the last element,
+ // which can happen if elements were removed.
+ while (mFirstPosition >= count && mFirstPosition > 0) {
+ mFirstPosition--;
+ }
+ } else {
+ // Some of the children survived the relayout. We will keep it in its place,
+ // but go through previous children and maybe add them.
+ if (!mWasZoomedIn) {
+ // If we were previously zoomed-in on a single item, ignore this and just
+ // use the default value set above. Reasoning: if we are still zoomed-in,
+ // oldTop will be ignored when laying out the single child element. If we
+ // are no longer zoomed in, then we want to position items using the top
+ // of the single item as if the single item was not zoomed in, which is
+ // equal to the default value.
+ oldTop = getChildAt(index).getTop();
+ }
+ while (oldTop > getPaddingTop() && position > 0) {
+ position--;
+ oldTop -= getItemHeight();
+ }
+ if (position == 0 && oldTop > getCentralViewTop()) {
+ // We need to handle special case where the first, central item was removed
+ // and now the first element is hanging below, instead of being nicely
+ // centered.
+ oldTop = getCentralViewTop();
+ }
+ mFirstPosition = position;
+ }
+ } else if (mPushFirstHigher) {
+ // We are trying to position elements ourselves, so we force position of the first
+ // one.
+ oldTop = getCentralViewTop() - getItemHeight();
+ }
+
+ performLayoutChildren(recycler, state, parentBottom, oldTop);
+
+ // Since the content might have changed, we need to adjust the absolute scroll in case
+ // some elements have disappeared or were added.
+ if (getChildCount() == 0) {
+ setAbsoluteScroll(0);
+ } else {
+ View child = getChildAt(findCenterViewIndex());
+ setAbsoluteScroll(child.getTop() - getCentralViewTop() + getPosition(child) *
+ getItemHeight());
+ }
+
+ mUseOldViewTop = true;
+ mPushFirstHigher = false;
+ }
+
+ private void performLayoutChildren(Recycler recycler, State state, int parentBottom,
+ int top) {
+ detachAndScrapAttachedViews(recycler);
+
+ if (mMaximizeSingleItem && state.getItemCount() == 1) {
+ performLayoutOneChild(recycler, parentBottom);
+ mWasZoomedIn = true;
+ } else {
+ performLayoutMultipleChildren(recycler, state, parentBottom, top);
+ mWasZoomedIn = false;
+ }
+
+ if (getChildCount() > 0) {
+ post(mNotifyChildrenPostLayoutRunnable);
+ }
+ }
+
+ private void performLayoutOneChild(Recycler recycler, int parentBottom) {
+ final int right = getWidth() - getPaddingRight();
+ View v = recycler.getViewForPosition(getFirstPosition());
+ addView(v, 0);
+ measureZoomView(v);
+ v.layout(getPaddingLeft(), getPaddingTop(), right, parentBottom);
+ }
+
+ private void performLayoutMultipleChildren(Recycler recycler, State state, int parentBottom,
+ int top) {
+ int bottom;
+ final int left = getPaddingLeft();
+ final int right = getWidth() - getPaddingRight();
+ final int count = state.getItemCount();
+ // If we are laying out children with center element being different than the first, we
+ // need to start with previous child which appears half visible at the top.
+ for (int i = 0; getFirstPosition() + i < count; i++, top = bottom) {
+ if (top >= parentBottom) {
+ break;
+ }
+ View v = recycler.getViewForPosition(getFirstPosition() + i);
+ addView(v, i);
+ measureThirdView(v);
+ bottom = top + getItemHeight();
+ v.layout(left, top, right, bottom);
+ }
+ }
+
+ private void setAbsoluteScroll(int absoluteScroll) {
+ mAbsoluteScroll = absoluteScroll;
+ for (OnScrollListener listener : mOnScrollListeners) {
+ listener.onAbsoluteScrollChange(mAbsoluteScroll);
+ }
+ }
+
+ private void measureView(View v, int height) {
+ final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+ final int widthSpec = getChildMeasureSpec(getWidth(),
+ getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin, lp.width,
+ canScrollHorizontally());
+ final int heightSpec = getChildMeasureSpec(getHeight(),
+ getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin,
+ height, canScrollVertically());
+ v.measure(widthSpec, heightSpec);
+ }
+
+ private void measureThirdView(View v) {
+ measureView(v, (int) (1 + (float) getHeight() / THIRD));
+ }
+
+ private void measureZoomView(View v) {
+ measureView(v, getHeight());
+ }
+
+ @Override
+ public RecyclerView.LayoutParams generateDefaultLayoutParams() {
+ return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ }
+
+ @Override
+ public boolean canScrollVertically() {
+ // Disable vertical scrolling when zoomed.
+ return getItemCount() != 1 || !mWasZoomedIn;
+ }
+
+ @Override
+ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, State state) {
+ // TODO(gruszczy): This code is shit, needs to be rewritten.
+ if (getChildCount() == 0) {
+ return 0;
+ }
+ int scrolled = 0;
+ final int left = getPaddingLeft();
+ final int right = getWidth() - getPaddingRight();
+ if (dy < 0) {
+ while (scrolled > dy) {
+ final View topView = getChildAt(0);
+ if (getFirstPosition() > 0) {
+ final int hangingTop = Math.max(-topView.getTop(), 0);
+ final int scrollBy = Math.min(scrolled - dy, hangingTop);
+ scrolled -= scrollBy;
+ offsetChildrenVertical(scrollBy);
+ if (getFirstPosition() > 0 && scrolled > dy) {
+ mFirstPosition--;
+ View v = recycler.getViewForPosition(getFirstPosition());
+ addView(v, 0);
+ measureThirdView(v);
+ final int bottom = topView.getTop();
+ final int top = bottom - getItemHeight();
+ v.layout(left, top, right, bottom);
+ } else {
+ break;
+ }
+ } else {
+ mPushFirstHigher = false;
+ int maxScroll = mOverScrollListener!= null ?
+ getHeight() : getTopViewMaxTop();
+ final int scrollBy = Math.min(-dy + scrolled, maxScroll - topView.getTop());
+ scrolled -= scrollBy;
+ offsetChildrenVertical(scrollBy);
+ break;
+ }
+ }
+ } else if (dy > 0) {
+ final int parentHeight = getHeight();
+ while (scrolled < dy) {
+ final View bottomView = getChildAt(getChildCount() - 1);
+ if (state.getItemCount() > mFirstPosition + getChildCount()) {
+ final int hangingBottom =
+ Math.max(bottomView.getBottom() - parentHeight, 0);
+ final int scrollBy = -Math.min(dy - scrolled, hangingBottom);
+ scrolled -= scrollBy;
+ offsetChildrenVertical(scrollBy);
+ if (scrolled < dy) {
+ View v = recycler.getViewForPosition(mFirstPosition + getChildCount());
+ final int top = getChildAt(getChildCount() - 1).getBottom();
+ addView(v);
+ measureThirdView(v);
+ final int bottom = top + getItemHeight();
+ v.layout(left, top, right, bottom);
+ } else {
+ break;
+ }
+ } else {
+ final int scrollBy =
+ Math.max(-dy + scrolled, getHeight() / 2 - bottomView.getBottom());
+ scrolled -= scrollBy;
+ offsetChildrenVertical(scrollBy);
+ break;
+ }
+ }
+ }
+ recycleViewsOutOfBounds(recycler);
+ setAbsoluteScroll(mAbsoluteScroll + scrolled);
+ return scrolled;
+ }
+
+ @Override
+ public void scrollToPosition(int position) {
+ mUseOldViewTop = false;
+ if (position > 0) {
+ mFirstPosition = position - 1;
+ mPushFirstHigher = true;
+ } else {
+ mFirstPosition = position;
+ mPushFirstHigher = false;
+ }
+ requestLayout();
+ }
+
+ public void setCustomSmoothScroller(RecyclerView.SmoothScroller smoothScroller) {
+ mSmoothScroller = smoothScroller;
+ }
+
+ public void clearCustomSmoothScroller() {
+ mSmoothScroller = null;
+ }
+
+ public RecyclerView.SmoothScroller getDefaultSmoothScroller(RecyclerView recyclerView) {
+ if (mDefaultSmoothScroller == null) {
+ mDefaultSmoothScroller = new SmoothScroller(
+ recyclerView.getContext(), this);
+ }
+ return mDefaultSmoothScroller;
+ }
+ @Override
+ public void smoothScrollToPosition(RecyclerView recyclerView, State state,
+ int position) {
+ RecyclerView.SmoothScroller scroller = mSmoothScroller;
+ if (scroller == null) {
+ scroller = getDefaultSmoothScroller(recyclerView);
+ }
+ scroller.setTargetPosition(position);
+ startSmoothScroll(scroller);
+ }
+
+ private void recycleViewsOutOfBounds(RecyclerView.Recycler recycler) {
+ final int childCount = getChildCount();
+ final int parentWidth = getWidth();
+ // Here we want to use real height, so we don't remove views that are only visible in
+ // padded section.
+ final int parentHeight = getHeight();
+ boolean foundFirst = false;
+ int first = 0;
+ int last = 0;
+ for (int i = 0; i < childCount; i++) {
+ final View v = getChildAt(i);
+ if (v.hasFocus() || (v.getRight() >= 0 && v.getLeft() <= parentWidth &&
+ v.getBottom() >= 0 && v.getTop() <= parentHeight)) {
+ if (!foundFirst) {
+ first = i;
+ foundFirst = true;
+ }
+ last = i;
+ }
+ }
+ for (int i = childCount - 1; i > last; i--) {
+ removeAndRecycleViewAt(i, recycler);
+ }
+ for (int i = first - 1; i >= 0; i--) {
+ removeAndRecycleViewAt(i, recycler);
+ }
+ if (getChildCount() == 0) {
+ mFirstPosition = 0;
+ } else if (first > 0) {
+ mPushFirstHigher = true;
+ mFirstPosition += first;
+ }
+ }
+
+ public int getFirstPosition() {
+ return mFirstPosition;
+ }
+
+ @Override
+ public void onAdapterChanged(RecyclerView.Adapter oldAdapter,
+ RecyclerView.Adapter newAdapter) {
+ removeAllViews();
+ }
+ }
+
+ /**
+ * Interface for receiving callbacks when WearableListView children become or cease to be the
+ * central item.
+ */
+ public interface OnCenterProximityListener {
+ /**
+ * Called when this view becomes central item of the WearableListView.
+ *
+ * @param animate Whether you should animate your transition of the View to become the
+ * central item. If false, this is the initial setting and you should
+ * transition immediately.
+ */
+ void onCenterPosition(boolean animate);
+
+ /**
+ * Called when this view stops being the central item of the WearableListView.
+ * @param animate Whether you should animate your transition of the View to being
+ * non central item. If false, this is the initial setting and you should
+ * transition immediately.
+ */
+ void onNonCenterPosition(boolean animate);
+ }
+
+ /**
+ * Interface for listening for click events on WearableListView.
+ */
+ public interface ClickListener {
+ /**
+ * Called when the central child of the WearableListView is tapped.
+ * @param view View that was clicked.
+ */
+ public void onClick(ViewHolder view);
+
+ /**
+ * Called when the user taps the top third of the WearableListView and no item is present
+ * there. This can happen when you are in initial state and the first, top-most item of the
+ * WearableListView is centered.
+ */
+ public void onTopEmptyRegionClick();
+ }
+
+ /**
+ * @hide
+ */
+ public interface OnOverScrollListener {
+ public void onOverScroll();
+ }
+
+ /**
+ * Interface for listening to WearableListView content scrolling.
+ */
+ public interface OnScrollListener {
+ /**
+ * Called when the content is scrolled, reporting the relative scroll value.
+ * @param scroll Amount the content was scrolled. This is a delta from the previous
+ * position to the new position.
+ */
+ public void onScroll(int scroll);
+
+ /**
+ * Called when the content is scrolled, reporting the absolute scroll value.
+ *
+ * @deprecated BE ADVISED DO NOT USE THIS This might provide wrong values when contents
+ * of a RecyclerView change.
+ *
+ * @param scroll Absolute scroll position of the content inside the WearableListView.
+ */
+ @Deprecated
+ public void onAbsoluteScrollChange(int scroll);
+
+ /**
+ * Called when WearableListView's scroll state changes.
+ *
+ * @param scrollState The updated scroll state. One of {@link #SCROLL_STATE_IDLE},
+ * {@link #SCROLL_STATE_DRAGGING} or {@link #SCROLL_STATE_SETTLING}.
+ */
+ public void onScrollStateChanged(int scrollState);
+
+ /**
+ * Called when the central item of the WearableListView changes.
+ *
+ * @param centralPosition Position of the item in the Adapter.
+ */
+ public void onCentralPositionChanged(int centralPosition);
+ }
+
+ /**
+ * A listener interface that can be added to the WearableListView to get notified when the
+ * central item is changed.
+ */
+ public interface OnCentralPositionChangedListener {
+ /**
+ * Called when the central item of the WearableListView changes.
+ *
+ * @param centralPosition Position of the item in the Adapter.
+ */
+ void onCentralPositionChanged(int centralPosition);
+ }
+
+ /**
+ * Base class for adapters providing data for the WearableListView. For details refer to
+ * RecyclerView.Adapter.
+ */
+ public static abstract class Adapter extends RecyclerView.Adapter<ViewHolder> {
+ }
+
+ private static class SmoothScroller extends LinearSmoothScroller {
+
+ private static final float MILLISECONDS_PER_INCH = 100f;
+
+ private final LayoutManager mLayoutManager;
+
+ public SmoothScroller(Context context, WearableListView.LayoutManager manager) {
+ super(context);
+ mLayoutManager = manager;
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ }
+
+ // TODO: (mindyp): when flinging, return the dydt that triggered the fling.
+ @Override
+ protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
+ return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
+ }
+
+ @Override
+ public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int
+ snapPreference) {
+ // Snap to center.
+ return (boxStart + boxEnd) / 2 - (viewStart + viewEnd) / 2;
+ }
+
+ @Override
+ public PointF computeScrollVectorForPosition(int targetPosition) {
+ if (targetPosition < mLayoutManager.getFirstPosition()) {
+ return new PointF(0, -1);
+ } else {
+ return new PointF(0, 1);
+ }
+ }
+ }
+
+ /**
+ * Wrapper around items displayed in the list view. {@link .Adapter} must return objects that
+ * are instances of this class. Consider making the wrapped View implement
+ * {@link .OnCenterProximityListener} if you want to receive a callback when it becomes or
+ * ceases to be the central item in the WearableListView.
+ */
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+ public ViewHolder(View itemView) {
+ super(itemView);
+ }
+
+ /**
+ * Called when the wrapped view is becoming or ceasing to be the central item of the
+ * WearableListView.
+ *
+ * Retained as protected for backwards compatibility.
+ *
+ * @hide
+ */
+ protected void onCenterProximity(boolean isCentralItem, boolean animate) {
+ if (!(itemView instanceof OnCenterProximityListener)) {
+ return;
+ }
+ OnCenterProximityListener item = (OnCenterProximityListener) itemView;
+ if (isCentralItem) {
+ item.onCenterPosition(animate);
+ } else {
+ item.onNonCenterPosition(animate);
+ }
+ }
+ }
+
+ private class SetScrollVerticallyProperty extends Property<WearableListView, Integer> {
+ public SetScrollVerticallyProperty() {
+ super(Integer.class, "scrollVertically");
+ }
+
+ @Override
+ public Integer get(WearableListView wearableListView) {
+ return wearableListView.mLastScrollChange;
+ }
+
+ @Override
+ public void set(WearableListView wearableListView, Integer value) {
+ wearableListView.setScrollVertically(value);
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/DeviceUtils.java b/src/com/android/packageinstaller/DeviceUtils.java
new file mode 100644
index 00000000..8e2d57ea
--- /dev/null
+++ b/src/com/android/packageinstaller/DeviceUtils.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.packageinstaller;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+
+public class DeviceUtils {
+ public static boolean isTelevision(Context context) {
+ int uiMode = context.getResources().getConfiguration().uiMode;
+ return (uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION;
+ }
+
+ public static boolean isWear(final Context context) {
+ return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+ }
+}
diff --git a/src/com/android/packageinstaller/InstallFlowAnalytics.java b/src/com/android/packageinstaller/InstallFlowAnalytics.java
index 2fc6db37..4591f31c 100644
--- a/src/com/android/packageinstaller/InstallFlowAnalytics.java
+++ b/src/com/android/packageinstaller/InstallFlowAnalytics.java
@@ -85,6 +85,11 @@ public class InstallFlowAnalytics implements Parcelable {
*/
static final byte RESULT_PACKAGE_MANAGER_INSTALL_FAILED = 6;
+ /**
+ * Installation blocked since this feature is not allowed on Android Wear devices yet.
+ */
+ static final byte RESULT_NOT_ALLOWED_ON_WEAR = 7;
+
private static final int FLAG_INSTALLS_FROM_UNKNOWN_SOURCES_PERMITTED = 1 << 0;
private static final int FLAG_INSTALL_REQUEST_FROM_UNKNOWN_SOURCE = 1 << 1;
private static final int FLAG_VERIFY_APPS_ENABLED = 1 << 2;
@@ -600,4 +605,4 @@ public class InstallFlowAnalytics implements Parcelable {
}
return digest.digest();
}
-} \ No newline at end of file
+}
diff --git a/src/com/android/packageinstaller/PackageInstallerActivity.java b/src/com/android/packageinstaller/PackageInstallerActivity.java
index 6bcd80e4..868872a9 100644
--- a/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -110,6 +110,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen
private static final int DLG_INSTALL_ERROR = DLG_BASE + 4;
private static final int DLG_ALLOW_SOURCE = DLG_BASE + 5;
private static final int DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES = DLG_BASE + 6;
+ private static final int DLG_NOT_SUPPORTED_ON_WEAR = DLG_BASE + 7;
private void startInstallConfirm() {
TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost);
@@ -293,7 +294,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen
Log.i(TAG, "Canceling installation");
finish();
}
- })
+ })
.setOnCancelListener(this)
.create();
case DLG_INSTALL_ERROR :
@@ -333,6 +334,18 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen
})
.setOnCancelListener(this)
.create();
+ case DLG_NOT_SUPPORTED_ON_WEAR:
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.wear_not_allowed_dlg_title)
+ .setMessage(R.string.wear_not_allowed_dlg_text)
+ .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ setResult(RESULT_OK);
+ finish();
+ }
+ })
+ .setOnCancelListener(this)
+ .create();
}
return null;
}
@@ -478,6 +491,13 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen
mInstallFlowAnalytics.setAppVerifierInstalled(isAppVerifierInstalled());
mInstallFlowAnalytics.setPackageUri(mPackageURI.toString());
+ if (DeviceUtils.isWear(this)) {
+ showDialogInner(DLG_NOT_SUPPORTED_ON_WEAR);
+ mInstallFlowAnalytics.setFlowFinished(
+ InstallFlowAnalytics.RESULT_NOT_ALLOWED_ON_WEAR);
+ return;
+ }
+
final String scheme = mPackageURI.getScheme();
if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) {
Log.w(TAG, "Unsupported scheme " + scheme);
diff --git a/src/com/android/packageinstaller/permission/model/AppPermissions.java b/src/com/android/packageinstaller/permission/model/AppPermissions.java
index d465ee09..a0f23d64 100644
--- a/src/com/android/packageinstaller/permission/model/AppPermissions.java
+++ b/src/com/android/packageinstaller/permission/model/AppPermissions.java
@@ -23,6 +23,8 @@ import android.text.BidiFormatter;
import android.text.TextPaint;
import android.text.TextUtils;
+import com.android.packageinstaller.DeviceUtils;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -165,9 +167,12 @@ public final class AppPermissions {
private static CharSequence loadEllipsizedAppLabel(Context context, PackageInfo packageInfo) {
String label = packageInfo.applicationInfo.loadLabel(
context.getPackageManager()).toString();
- String noNewLineLabel = label.replace("\n", " ");
- String ellipsizedLabel = TextUtils.ellipsize(noNewLineLabel, sAppLabelEllipsizePaint,
+ String ellipsizedLabel = label.replace("\n", " ");
+ if (!DeviceUtils.isWear(context)) {
+ // Only ellipsize for non-Wear devices.
+ ellipsizedLabel = TextUtils.ellipsize(ellipsizedLabel, sAppLabelEllipsizePaint,
MAX_APP_LABEL_LENGTH_PIXELS, TextUtils.TruncateAt.END).toString();
+ }
return BidiFormatter.getInstance().unicodeWrap(ellipsizedLabel);
}
}
diff --git a/src/com/android/packageinstaller/permission/model/PermissionStatusReceiver.java b/src/com/android/packageinstaller/permission/model/PermissionStatusReceiver.java
index 2a46f1a6..810ae8ec 100644
--- a/src/com/android/packageinstaller/permission/model/PermissionStatusReceiver.java
+++ b/src/com/android/packageinstaller/permission/model/PermissionStatusReceiver.java
@@ -18,6 +18,7 @@ package com.android.packageinstaller.permission.model;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -30,37 +31,55 @@ import com.android.packageinstaller.permission.utils.Utils;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
public class PermissionStatusReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- int[] counts = new int[3];
- ArrayList<CharSequence> grantedGroups = new ArrayList<>();
- boolean succeeded = false;
+ if (Intent.ACTION_GET_PERMISSIONS_COUNT.equals(intent.getAction())) {
+ Intent responseIntent = new Intent(intent.getStringExtra(
+ Intent.EXTRA_GET_PERMISSIONS_RESPONSE_INTENT));
+ responseIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- boolean isForPackage = intent.hasExtra(Intent.EXTRA_PACKAGE_NAME);
+ int[] counts = new int[3];
+ ArrayList<CharSequence> grantedGroups = new ArrayList<>();
+ boolean succeeded = false;
- Intent responseIntent = new Intent(intent.getStringExtra(
- Intent.EXTRA_GET_PERMISSIONS_RESPONSE_INTENT));
- responseIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-
-
- if (isForPackage) {
- String pkg = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
- succeeded = getPermissionsCount(context, pkg, counts, grantedGroups);
- } else {
- succeeded = getAppsWithPermissionsCount(context, counts);
- }
- if (succeeded) {
- responseIntent.putExtra(Intent.EXTRA_GET_PERMISSIONS_COUNT_RESULT, counts);
+ boolean isForPackage = intent.hasExtra(Intent.EXTRA_PACKAGE_NAME);
if (isForPackage) {
- responseIntent.putExtra(Intent.EXTRA_GET_PERMISSIONS_GROUP_LIST_RESULT,
- grantedGroups.toArray(new CharSequence[grantedGroups.size()]));
+ String pkg = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ succeeded = getPermissionsCount(context, pkg, counts, grantedGroups);
+ } else {
+ succeeded = getAppsWithPermissionsCount(context, counts);
}
- }
+ if (succeeded) {
+ responseIntent.putExtra(Intent.EXTRA_GET_PERMISSIONS_COUNT_RESULT, counts);
- context.sendBroadcast(responseIntent);
+ if (isForPackage) {
+ responseIntent.putExtra(Intent.EXTRA_GET_PERMISSIONS_GROUP_LIST_RESULT,
+ grantedGroups.toArray(new CharSequence[grantedGroups.size()]));
+ }
+ }
+ context.sendBroadcast(responseIntent);
+ } else if (Intent.ACTION_GET_PERMISSIONS_PACKAGES.equals(intent.getAction())) {
+ Intent responseIntent = new Intent(intent.getStringExtra(
+ Intent.EXTRA_GET_PERMISSIONS_PACKAGES_RESPONSE_INTENT));
+ responseIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+
+ List<String> appsList = new ArrayList<>();
+ List<CharSequence> appLabelsList = new ArrayList<>();
+ List<Boolean> isSystemAppList = new ArrayList<>();
+ if (getAppsWithRuntimePermissions(context, appsList, appLabelsList, isSystemAppList)) {
+ responseIntent.putExtra(Intent.EXTRA_GET_PERMISSIONS_APP_LIST_RESULT,
+ appsList.toArray(new String[appsList.size()]));
+ responseIntent.putExtra(Intent.EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT,
+ appLabelsList.toArray(new String[appLabelsList.size()]));
+ responseIntent.putExtra(Intent.EXTRA_GET_PERMISSIONS_IS_SYSTEM_APP_LIST_RESULT,
+ toPrimitiveBoolArray(isSystemAppList));
+ }
+ context.sendBroadcast(responseIntent);
+ }
}
public boolean getPermissionsCount(Context context, String pkg, int[] counts,
@@ -105,6 +124,42 @@ public class PermissionStatusReceiver extends BroadcastReceiver {
}
}
+ public boolean getAppsWithRuntimePermissions(Context context, List<String> appsList,
+ List<CharSequence> appLabelsList, List<Boolean> isSystemAppList) {
+ final List<ApplicationInfo> appInfos = Utils.getAllInstalledApplications(context);
+ if (appInfos == null) {
+ return false;
+ }
+ final int appInfosSize = appInfos.size();
+ try {
+ ArraySet<String> launcherPackages = Utils.getLauncherPackages(context);
+ for (int i = 0; i < appInfosSize; ++i) {
+ final String packageName = appInfos.get(i).packageName;
+ PackageInfo packageInfo = context.getPackageManager().getPackageInfo(
+ packageName, PackageManager.GET_PERMISSIONS);
+ AppPermissions appPermissions =
+ new AppPermissions(context, packageInfo, null, false, null);
+
+ boolean shouldShow = false;
+ for (AppPermissionGroup group : appPermissions.getPermissionGroups()) {
+ if (Utils.shouldShowPermission(group, packageName)) {
+ shouldShow = true;
+ break;
+ }
+ }
+ if (shouldShow) {
+ appsList.add(packageName);
+ appLabelsList.add(appPermissions.getAppLabel());
+ isSystemAppList.add(Utils.isSystem(appPermissions, launcherPackages));
+ }
+ }
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+
+ return true;
+ }
+
public boolean getAppsWithPermissionsCount(Context context, int[] counts) {
ArraySet<String> launcherPkgs = Utils.getLauncherPackages(context);
// Indexed by uid.
@@ -130,4 +185,14 @@ public class PermissionStatusReceiver extends BroadcastReceiver {
counts[1] = allApps.size();
return true;
}
+
+ private boolean[] toPrimitiveBoolArray(final List<Boolean> list) {
+ final int count = list.size();
+ final boolean[] result = new boolean[count];
+ for (int i = 0; i < count; ++i) {
+ result[i] = list.get(i);
+ }
+
+ return result;
+ }
}
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
index c8446039..102fd6ef 100644
--- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
+++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
@@ -39,6 +39,7 @@ import android.view.View;
import android.view.Window;
import android.view.WindowManager;
+import com.android.packageinstaller.DeviceUtils;
import com.android.packageinstaller.R;
import com.android.packageinstaller.permission.model.AppPermissionGroup;
import com.android.packageinstaller.permission.model.AppPermissions;
@@ -72,9 +73,11 @@ public class GrantPermissionsActivity extends OverlayTouchActivity
setTitle(R.string.permission_request_title);
- if (Utils.isTelevision(this)) {
+ if (DeviceUtils.isTelevision(this)) {
mViewHandler = new com.android.packageinstaller.permission.ui.television
.GrantPermissionsViewHandlerImpl(this).setResultListener(this);
+ } else if (DeviceUtils.isWear(this)) {
+ mViewHandler = new GrantPermissionsWatchViewHandler(this).setResultListener(this);
} else {
mViewHandler = new com.android.packageinstaller.permission.ui.handheld
.GrantPermissionsViewHandlerImpl(this).setResultListener(this);
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java b/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java
new file mode 100644
index 00000000..21042f00
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java
@@ -0,0 +1,176 @@
+package com.android.packageinstaller.permission.ui;
+
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.ui.wear.ConfirmationViewHandler;
+
+/**
+ * Watch-specific view handler for the grant permissions activity.
+ */
+final class GrantPermissionsWatchViewHandler extends ConfirmationViewHandler
+ implements GrantPermissionsViewHandler {
+ private static final String TAG = "GrantPermsWatchViewH";
+
+ private static final String ARG_GROUP_NAME = "ARG_GROUP_NAME";
+
+ private final Context mContext;
+
+ private ResultListener mResultListener;
+
+ private String mGroupName;
+ private boolean mShowDoNotAsk;
+
+ private CharSequence mMessage;
+ private String mCurrentPageText;
+ private Icon mIcon;
+
+ GrantPermissionsWatchViewHandler(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ @Override
+ public GrantPermissionsWatchViewHandler setResultListener(ResultListener listener) {
+ mResultListener = listener;
+ return this;
+ }
+
+ @Override
+ public View createView() {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "createView()");
+ }
+
+ mShowDoNotAsk = false;
+
+ return super.createView();
+ }
+
+ @Override
+ public void updateWindowAttributes(WindowManager.LayoutParams outLayoutParams) {
+ outLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
+ outLayoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;
+ outLayoutParams.format = PixelFormat.OPAQUE;
+ outLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+ outLayoutParams.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+ }
+
+ @Override
+ public void updateUi(String groupName, int groupCount, int groupIndex, Icon icon,
+ CharSequence message, boolean showDoNotAsk) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "updateUi() - groupName: " + groupName
+ + ", groupCount: " + groupCount
+ + ", groupIndex: " + groupIndex
+ + ", icon: " + icon
+ + ", message: " + message
+ + ", showDoNotAsk: " + showDoNotAsk);
+ }
+
+ mGroupName = groupName;
+ mShowDoNotAsk = showDoNotAsk;
+ mMessage = message;
+ mIcon = icon;
+ mCurrentPageText = (groupCount > 1 ?
+ mContext.getString(R.string.current_permission_template, groupIndex + 1, groupCount)
+ : null);
+
+ invalidate();
+ }
+
+ @Override
+ public void saveInstanceState(Bundle outState) {
+ outState.putString(ARG_GROUP_NAME, mGroupName);
+ }
+
+ @Override
+ public void loadInstanceState(Bundle savedInstanceState) {
+ mGroupName = savedInstanceState.getString(ARG_GROUP_NAME);
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (mResultListener != null) {
+ mResultListener.onPermissionGrantResult(mGroupName, false, false);
+ }
+ }
+
+ @Override // ConfirmationViewHandler
+ public void onButton1() {
+ onClick(true /* granted */, false /* doNotAskAgain */);
+ }
+
+ @Override // ConfirmationViewHandler
+ public void onButton2() {
+ onClick(false /* granted */, false /* doNotAskAgain */);
+ }
+
+ @Override // ConfirmationViewHandler
+ public void onButton3() {
+ onClick(false /* granted */, true /* doNotAskAgain */);
+ }
+
+ @Override // ConfirmationViewHandler
+ public CharSequence getCurrentPageText() {
+ return mCurrentPageText;
+ }
+
+ @Override // ConfirmationViewHandler
+ public Icon getPermissionIcon() {
+ return mIcon;
+ }
+
+ @Override // ConfirmationViewHandler
+ public CharSequence getMessage() {
+ return mMessage;
+ }
+
+ @Override // ConfirmationViewHandler
+ public int getButtonBarMode() {
+ return mShowDoNotAsk ? MODE_VERTICAL_BUTTONS : MODE_HORIZONTAL_BUTTONS;
+ }
+
+ @Override // ConfirmationViewHandler
+ public CharSequence getVerticalButton1Text() {
+ return mContext.getString(R.string.grant_dialog_button_allow);
+ }
+
+ @Override // ConfirmationViewHandler
+ public CharSequence getVerticalButton2Text() {
+ return mContext.getString(R.string.grant_dialog_button_deny);
+ }
+
+ @Override // ConfirmationViewHandler
+ public CharSequence getVerticalButton3Text() {
+ return mContext.getString(R.string.grant_dialog_button_deny_dont_ask_again);
+ }
+
+ @Override // ConfirmationViewHandler
+ public Drawable getVerticalButton1Icon(){
+ return mContext.getDrawable(R.drawable.confirm_button);
+ }
+
+ @Override // ConfirmationViewHandler
+ public Drawable getVerticalButton2Icon(){
+ return mContext.getDrawable(R.drawable.cancel_button);
+ }
+
+ @Override // ConfirmationViewHandler
+ public Drawable getVerticalButton3Icon(){
+ return mContext.getDrawable(R.drawable.deny_button);
+ }
+
+ private void onClick(boolean granted, boolean doNotAskAgain) {
+ if (mResultListener != null) {
+ mResultListener.onPermissionGrantResult(mGroupName, granted, doNotAskAgain);
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java b/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
index f5703564..fad35e17 100644
--- a/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
+++ b/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
@@ -20,7 +20,9 @@ import android.app.Fragment;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
+import com.android.packageinstaller.permission.ui.wear.AppPermissionsFragmentWear;
import com.android.packageinstaller.permission.utils.Utils;
+import com.android.packageinstaller.DeviceUtils;
public final class ManagePermissionsActivity extends OverlayTouchActivity {
private static final String LOG_TAG = "ManagePermissionsActivity";
@@ -54,7 +56,9 @@ public final class ManagePermissionsActivity extends OverlayTouchActivity {
finish();
return;
}
- if (Utils.isTelevision(this)) {
+ if (DeviceUtils.isWear(this)) {
+ fragment = AppPermissionsFragmentWear.newInstance(packageName);
+ } else if (Utils.isTelevision(this)) {
fragment = com.android.packageinstaller.permission.ui.television
.AppPermissionsFragment.newInstance(packageName);
} else {
diff --git a/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java b/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java
index e41e05fb..0f240bef 100644
--- a/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java
@@ -39,6 +39,7 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.packageinstaller.DeviceUtils;
import com.android.packageinstaller.R;
import com.android.packageinstaller.permission.model.AppPermissionGroup;
import com.android.packageinstaller.permission.model.PermissionApps;
@@ -186,7 +187,7 @@ public final class PermissionAppsFragment extends PermissionsFrameFragment imple
return;
}
- boolean isTelevision = Utils.isTelevision(context);
+ boolean isTelevision = DeviceUtils.isTelevision(context);
PreferenceScreen screen = getPreferenceScreen();
ArraySet<String> preferencesToRemove = new ArraySet<>();
diff --git a/src/com/android/packageinstaller/permission/ui/wear/AppPermissionsFragmentWear.java b/src/com/android/packageinstaller/permission/ui/wear/AppPermissionsFragmentWear.java
new file mode 100644
index 00000000..aba97fc8
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/wear/AppPermissionsFragmentWear.java
@@ -0,0 +1,335 @@
+/*
+* Copyright (C) 2015 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.android.packageinstaller.permission.ui.wear;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.support.wearable.view.WearableListView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.model.AppPermissionGroup;
+import com.android.packageinstaller.permission.model.AppPermissions;
+import com.android.packageinstaller.permission.ui.OverlayTouchActivity;
+import com.android.packageinstaller.permission.ui.wear.settings.PermissionsSettingsAdapter;
+import com.android.packageinstaller.permission.ui.wear.settings.SettingsAdapter;
+import com.android.packageinstaller.permission.utils.LocationUtils;
+import com.android.packageinstaller.permission.utils.SafetyNetLogger;
+import com.android.packageinstaller.permission.utils.Utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class AppPermissionsFragmentWear extends TitledSettingsFragment {
+
+ private static final String LOG_TAG = "ManagePermsFragment";
+
+ private static final int WARNING_CONFIRMATION_REQUEST = 252;
+ private List<AppPermissionGroup> mToggledGroups;
+ private AppPermissions mAppPermissions;
+ private PermissionsSettingsAdapter mAdapter;
+
+ private boolean mHasConfirmedRevoke;
+
+ public static AppPermissionsFragmentWear newInstance(String packageName) {
+ return setPackageName(new AppPermissionsFragmentWear(), packageName);
+ }
+
+ private static <T extends Fragment> T setPackageName(T fragment, String packageName) {
+ Bundle arguments = new Bundle();
+ arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
+ fragment.setArguments(arguments);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
+ Activity activity = getActivity();
+ PackageManager pm = activity.getPackageManager();
+ PackageInfo packageInfo;
+
+ try {
+ packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e);
+ packageInfo = null;
+ }
+
+ if (packageInfo == null) {
+ Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show();
+ activity.finish();
+ return;
+ }
+
+ mAppPermissions = new AppPermissions(activity, packageInfo, null, true, new Runnable() {
+ @Override
+ public void run() {
+ getActivity().finish();
+ }
+ });
+
+ mAdapter = new PermissionsSettingsAdapter(getContext());
+
+ initializePermissionGroupList();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.settings, container, false);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mAppPermissions.refresh();
+
+ // Also refresh the UI
+ final int count = mAdapter.getItemCount();
+ for (int i = 0; i < count; ++i) {
+ updatePermissionGroupSetting(i);
+ }
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ if (mAppPermissions != null) {
+ initializeLayout(mAdapter);
+ bindHeader(mAppPermissions.getPackageInfo());
+ }
+ }
+
+ private void bindHeader(PackageInfo packageInfo) {
+ Activity activity = getActivity();
+ PackageManager pm = activity.getPackageManager();
+ ApplicationInfo appInfo = packageInfo.applicationInfo;
+ CharSequence label = appInfo.loadLabel(pm);
+ mHeader.setText(label);
+ }
+
+ private void initializePermissionGroupList() {
+ final String packageName = mAppPermissions.getPackageInfo().packageName;
+ List<AppPermissionGroup> groups = mAppPermissions.getPermissionGroups();
+ List<SettingsAdapter.Setting<AppPermissionGroup>> nonSystemGroups = new ArrayList<>();
+
+ final int count = groups.size();
+ for (int i = 0; i < count; ++i) {
+ final AppPermissionGroup group = groups.get(i);
+ if (!Utils.shouldShowPermission(group, packageName)) {
+ continue;
+ }
+
+ boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG);
+
+ SettingsAdapter.Setting<AppPermissionGroup> setting =
+ new SettingsAdapter.Setting<AppPermissionGroup>(
+ group.getLabel(),
+ getPermissionGroupIcon(group),
+ i);
+ setting.data = group;
+
+ // The UI shows System settings first, then non-system settings
+ if (isPlatform) {
+ mAdapter.addSetting(setting);
+ } else {
+ nonSystemGroups.add(setting);
+ }
+ }
+
+ // Now add the non-system settings to the end of the list
+ final int nonSystemCount = nonSystemGroups.size();
+ for (int i = 0; i < nonSystemCount; ++i) {
+ final SettingsAdapter.Setting<AppPermissionGroup> setting = nonSystemGroups.get(i);
+ mAdapter.addSetting(setting);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ logAndClearToggledGroups();
+ }
+
+ @Override
+ public void onClick(WearableListView.ViewHolder view) {
+ final int index = view.getPosition();
+ SettingsAdapter.Setting<AppPermissionGroup> setting = mAdapter.get(index);
+ final AppPermissionGroup group = setting.data;
+
+ if (group == null) {
+ Log.e(LOG_TAG, "Error: AppPermissionGroup is null");
+ return;
+ }
+
+ // The way WearableListView is designed, there is no way to avoid this click handler
+ // Since the policy is fixed, ignore the click as the user is not able to change the state
+ // of this permission group
+ if (group.isPolicyFixed()) {
+ return;
+ }
+
+ OverlayTouchActivity activity = (OverlayTouchActivity) getActivity();
+ if (activity.isObscuredTouch()) {
+ activity.showOverlayDialog();
+ return;
+ }
+
+ addToggledGroup(group);
+
+ if (LocationUtils.isLocationGroupAndProvider(group.getName(), group.getApp().packageName)) {
+ LocationUtils.showLocationDialog(getContext(), mAppPermissions.getAppLabel());
+ return;
+ }
+
+ if (!group.areRuntimePermissionsGranted()) {
+ group.grantRuntimePermissions(false);
+ } else {
+ final boolean grantedByDefault = group.hasGrantedByDefaultPermission();
+ if (grantedByDefault || (!group.hasRuntimePermission() && !mHasConfirmedRevoke)) {
+ Intent intent = new Intent(getActivity(), WarningConfirmationActivity.class);
+ intent.putExtra(WarningConfirmationActivity.EXTRA_WARNING_MESSAGE,
+ getString(grantedByDefault ?
+ R.string.system_warning : R.string.old_sdk_deny_warning));
+ intent.putExtra(WarningConfirmationActivity.EXTRA_INDEX, index);
+ startActivityForResult(intent, WARNING_CONFIRMATION_REQUEST);
+ } else {
+ group.revokeRuntimePermissions(false);
+ }
+ }
+
+ updatePermissionGroupSetting(index);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == WARNING_CONFIRMATION_REQUEST) {
+ if (resultCode == Activity.RESULT_OK) {
+ int index = data.getIntExtra(WarningConfirmationActivity.EXTRA_INDEX, -1);
+ if (index == -1) {
+ Log.e(LOG_TAG, "Warning confirmation request came back with no index.");
+ return;
+ }
+
+ SettingsAdapter.Setting<AppPermissionGroup> setting = mAdapter.get(index);
+ final AppPermissionGroup group = setting.data;
+ group.revokeRuntimePermissions(false);
+ if (!group.hasGrantedByDefaultPermission()) {
+ mHasConfirmedRevoke = true;
+ }
+
+ updatePermissionGroupSetting(index);
+ }
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
+ private void updatePermissionGroupSetting(int index) {
+ SettingsAdapter.Setting<AppPermissionGroup> setting = mAdapter.get(index);
+ AppPermissionGroup group = setting.data;
+ mAdapter.updateSetting(
+ index,
+ group.getLabel(),
+ getPermissionGroupIcon(group),
+ group);
+ }
+
+ private void addToggledGroup(AppPermissionGroup group) {
+ if (mToggledGroups == null) {
+ mToggledGroups = new ArrayList<>();
+ }
+ // Double toggle is back to initial state.
+ if (mToggledGroups.contains(group)) {
+ mToggledGroups.remove(group);
+ } else {
+ mToggledGroups.add(group);
+ }
+ }
+
+ private void logAndClearToggledGroups() {
+ if (mToggledGroups != null) {
+ String packageName = mAppPermissions.getPackageInfo().packageName;
+ SafetyNetLogger.logPermissionsToggled(packageName, mToggledGroups);
+ mToggledGroups = null;
+ }
+ }
+
+ private int getPermissionGroupIcon(AppPermissionGroup group) {
+ String groupName = group.getName();
+ boolean isEnabled = group.areRuntimePermissionsGranted();
+ int resId;
+
+ switch (groupName) {
+ case Manifest.permission_group.CALENDAR:
+ resId = isEnabled ? R.drawable.ic_permission_calendar
+ : R.drawable.ic_permission_calendardisable;
+ break;
+ case Manifest.permission_group.CAMERA:
+ resId = isEnabled ? R.drawable.ic_permission_camera
+ : R.drawable.ic_permission_cameradisable;
+ break;
+ case Manifest.permission_group.CONTACTS:
+ resId = isEnabled ? R.drawable.ic_permission_contact
+ : R.drawable.ic_permission_contactdisable;
+ break;
+ case Manifest.permission_group.LOCATION:
+ resId = isEnabled ? R.drawable.ic_permission_location
+ : R.drawable.ic_permission_locationdisable;
+ break;
+ case Manifest.permission_group.MICROPHONE:
+ resId = isEnabled ? R.drawable.ic_permission_mic
+ : R.drawable.ic_permission_micdisable;
+ break;
+ case Manifest.permission_group.PHONE:
+ resId = isEnabled ? R.drawable.ic_permission_call
+ : R.drawable.ic_permission_calldisable;
+ break;
+ case Manifest.permission_group.SENSORS:
+ resId = isEnabled ? R.drawable.ic_permission_sensor
+ : R.drawable.ic_permission_sensordisable;
+ break;
+ case Manifest.permission_group.SMS:
+ resId = isEnabled ? R.drawable.ic_permission_sms
+ : R.drawable.ic_permission_smsdisable;
+ break;
+ case Manifest.permission_group.STORAGE:
+ resId = isEnabled ? R.drawable.ic_permission_storage
+ : R.drawable.ic_permission_storagedisable;
+ break;
+ default:
+ resId = isEnabled ? R.drawable.ic_permission_shield
+ : R.drawable.ic_permission_shielddisable;
+ }
+
+ return resId;
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/wear/ConfirmationViewHandler.java b/src/com/android/packageinstaller/permission/ui/wear/ConfirmationViewHandler.java
new file mode 100644
index 00000000..1c55e1bd
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/wear/ConfirmationViewHandler.java
@@ -0,0 +1,381 @@
+package com.android.packageinstaller.permission.ui.wear;
+
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.android.packageinstaller.R;
+
+public abstract class ConfirmationViewHandler implements
+ Handler.Callback,
+ View.OnClickListener,
+ ViewTreeObserver.OnScrollChangedListener,
+ ViewTreeObserver.OnGlobalLayoutListener {
+ private static final String TAG = "ConfirmationViewHandler";
+
+ public static final int MODE_HORIZONTAL_BUTTONS = 0;
+ public static final int MODE_VERTICAL_BUTTONS = 1;
+
+ private static final int MSG_SHOW_BUTTON_BAR = 1001;
+ private static final int MSG_HIDE_BUTTON_BAR = 1002;
+ private static final long HIDE_ANIM_DURATION = 500;
+
+ private View mRoot;
+ private TextView mCurrentPageText;
+ private ImageView mIcon;
+ private TextView mMessage;
+ private ScrollView mScrollingContainer;
+ private ViewGroup mContent;
+ private ViewGroup mHorizontalButtonBar;
+ private ViewGroup mVerticalButtonBar;
+ private Button mVerticalButton1;
+ private Button mVerticalButton2;
+ private Button mVerticalButton3;
+ private View mButtonBarContainer;
+
+ private Context mContext;
+
+ private Handler mHideHandler;
+ private Interpolator mInterpolator;
+ private float mButtonBarFloatingHeight;
+ private ObjectAnimator mButtonBarAnimator;
+ private float mCurrentTranslation;
+ private boolean mHiddenBefore;
+
+ // TODO: Move these into a builder
+ /** In the 2 button layout, this is allow button */
+ public abstract void onButton1();
+ /** In the 2 button layout, this is deny button */
+ public abstract void onButton2();
+ public abstract void onButton3();
+ public abstract CharSequence getVerticalButton1Text();
+ public abstract CharSequence getVerticalButton2Text();
+ public abstract CharSequence getVerticalButton3Text();
+ public abstract Drawable getVerticalButton1Icon();
+ public abstract Drawable getVerticalButton2Icon();
+ public abstract Drawable getVerticalButton3Icon();
+ public abstract CharSequence getCurrentPageText();
+ public abstract Icon getPermissionIcon();
+ public abstract CharSequence getMessage();
+
+ public ConfirmationViewHandler(Context context) {
+ mContext = context;
+ }
+
+ public View createView() {
+ mRoot = LayoutInflater.from(mContext).inflate(R.layout.confirmation_dialog, null);
+
+ mMessage = (TextView) mRoot.findViewById(R.id.message);
+ mCurrentPageText = (TextView) mRoot.findViewById(R.id.current_page_text);
+ mIcon = (ImageView) mRoot.findViewById(R.id.icon);
+ mButtonBarContainer = mRoot.findViewById(R.id.button_bar_container);
+ mContent = (ViewGroup) mRoot.findViewById(R.id.content);
+ mScrollingContainer = (ScrollView) mRoot.findViewById(R.id.scrolling_container);
+ mHorizontalButtonBar = (ViewGroup) mRoot.findViewById(R.id.horizontal_button_bar);
+ mVerticalButtonBar = (ViewGroup) mRoot.findViewById(R.id.vertical_button_bar);
+
+ Button horizontalAllow = (Button) mRoot.findViewById(R.id.permission_allow_button);
+ Button horizontalDeny = (Button) mRoot.findViewById(R.id.permission_deny_button);
+ horizontalAllow.setOnClickListener(this);
+ horizontalDeny.setOnClickListener(this);
+
+ mVerticalButton1 = (Button) mRoot.findViewById(R.id.vertical_button1);
+ mVerticalButton2 = (Button) mRoot.findViewById(R.id.vertical_button2);
+ mVerticalButton3 = (Button) mRoot.findViewById(R.id.vertical_button3);
+ mVerticalButton1.setOnClickListener(this);
+ mVerticalButton2.setOnClickListener(this);
+ mVerticalButton3.setOnClickListener(this);
+
+ mInterpolator = AnimationUtils.loadInterpolator(mContext,
+ android.R.interpolator.fast_out_slow_in);
+ mButtonBarFloatingHeight = mContext.getResources().getDimension(
+ R.dimen.conf_diag_floating_height);
+ mHideHandler = new Handler(Looper.getMainLooper(), this);
+
+ mScrollingContainer.getViewTreeObserver().addOnScrollChangedListener(this);
+ mRoot.getViewTreeObserver().addOnGlobalLayoutListener(this);
+
+ return mRoot;
+ }
+
+ /**
+ * Child class should override this for other modes. Call invalidate() to update the UI to the
+ * new button mode.
+ * @return The current mode the layout should use for the buttons
+ */
+ public int getButtonBarMode() {
+ return MODE_HORIZONTAL_BUTTONS;
+ }
+
+ public void invalidate() {
+ CharSequence currentPageText = getCurrentPageText();
+ if (!TextUtils.isEmpty(currentPageText)) {
+ mCurrentPageText.setText(currentPageText);
+ mCurrentPageText.setVisibility(View.VISIBLE);
+ } else {
+ mCurrentPageText.setVisibility(View.GONE);
+ }
+
+ Icon icon = getPermissionIcon();
+ if (icon != null) {
+ mIcon.setImageIcon(icon);
+ mIcon.setVisibility(View.VISIBLE);
+ } else {
+ mIcon.setVisibility(View.GONE);
+ }
+ mMessage.setText(getMessage());
+
+ switch (getButtonBarMode()) {
+ case MODE_HORIZONTAL_BUTTONS:
+ mHorizontalButtonBar.setVisibility(View.VISIBLE);
+ mVerticalButtonBar.setVisibility(View.GONE);
+ break;
+ case MODE_VERTICAL_BUTTONS:
+ mHorizontalButtonBar.setVisibility(View.GONE);
+ mVerticalButtonBar.setVisibility(View.VISIBLE);
+
+ mVerticalButton1.setText(getVerticalButton1Text());
+ mVerticalButton2.setText(getVerticalButton2Text());
+
+ mVerticalButton1.setCompoundDrawablesWithIntrinsicBounds(
+ getVerticalButton1Icon(), null, null, null);
+ mVerticalButton2.setCompoundDrawablesWithIntrinsicBounds(
+ getVerticalButton2Icon(), null, null, null);
+
+ CharSequence verticalButton3Text = getVerticalButton3Text();
+ if (TextUtils.isEmpty(verticalButton3Text)) {
+ mVerticalButton3.setVisibility(View.GONE);
+ } else {
+ mVerticalButton3.setText(getVerticalButton3Text());
+ mVerticalButton3.setCompoundDrawablesWithIntrinsicBounds(
+ getVerticalButton3Icon(), null, null, null);
+ }
+ break;
+ }
+
+ mScrollingContainer.scrollTo(0, 0);
+
+ mHideHandler.removeMessages(MSG_HIDE_BUTTON_BAR);
+ mHideHandler.removeMessages(MSG_SHOW_BUTTON_BAR);
+ }
+
+ @Override
+ public void onGlobalLayout() {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "onGlobalLayout");
+ Log.d(TAG, " contentHeight: " + mContent.getHeight());
+ }
+
+ if (mButtonBarAnimator != null) {
+ mButtonBarAnimator.cancel();
+ }
+
+ // In order to fake the buttons peeking at the bottom, need to do set the
+ // padding properly.
+ if (mContent.getPaddingBottom() != mButtonBarContainer.getHeight()) {
+ mContent.setPadding(mContent.getPaddingLeft(), mContent.getPaddingTop(),
+ mContent.getPaddingRight(), mButtonBarContainer.getHeight());
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, " set mContent.PaddingBottom: " + mButtonBarContainer.getHeight());
+ }
+ }
+
+ mButtonBarContainer.setTranslationY(mButtonBarContainer.getHeight());
+
+ // Give everything a chance to render
+ mHideHandler.removeMessages(MSG_HIDE_BUTTON_BAR);
+ mHideHandler.removeMessages(MSG_SHOW_BUTTON_BAR);
+ mHideHandler.sendEmptyMessageDelayed(MSG_SHOW_BUTTON_BAR, 50);
+ }
+
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+ switch (id) {
+ case R.id.permission_allow_button:
+ case R.id.vertical_button1:
+ onButton1();
+ break;
+ case R.id.permission_deny_button:
+ case R.id.vertical_button2:
+ onButton2();
+ break;
+ case R.id.vertical_button3:
+ onButton3();
+ break;
+ }
+ }
+
+ @Override
+ public boolean handleMessage (Message msg) {
+ switch (msg.what) {
+ case MSG_SHOW_BUTTON_BAR:
+ showButtonBar();
+ return true;
+ case MSG_HIDE_BUTTON_BAR:
+ hideButtonBar();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onScrollChanged () {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "onScrollChanged");
+ }
+ mHideHandler.removeMessages(MSG_HIDE_BUTTON_BAR);
+ hideButtonBar();
+ }
+
+ private void showButtonBar() {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "showButtonBar");
+ }
+
+ // Setup Button animation.
+ // pop the button bar back to full height, stop all animation
+ if (mButtonBarAnimator != null) {
+ mButtonBarAnimator.cancel();
+ }
+
+ // stop any calls to hide the button bar in the future
+ mHideHandler.removeMessages(MSG_HIDE_BUTTON_BAR);
+ mHiddenBefore = false;
+
+ // Evaluate the max height the button bar can go
+ final int screenHeight = mRoot.getHeight();
+ final int halfScreenHeight = screenHeight / 2;
+ final int buttonBarHeight = mButtonBarContainer.getHeight();
+ final int contentHeight = mContent.getHeight() - buttonBarHeight;
+ final int buttonBarMaxHeight =
+ Math.min(buttonBarHeight, halfScreenHeight);
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, " screenHeight: " + screenHeight);
+ Log.d(TAG, " contentHeight: " + contentHeight);
+ Log.d(TAG, " buttonBarHeight: " + buttonBarHeight);
+ Log.d(TAG, " buttonBarMaxHeight: " + buttonBarMaxHeight);
+ }
+
+ mButtonBarContainer.setTranslationZ(mButtonBarFloatingHeight);
+
+ // Only hide the button bar if it is occluding the content or the button bar is bigger than
+ // half the screen
+ if (contentHeight > (screenHeight - buttonBarHeight)
+ || buttonBarHeight > halfScreenHeight) {
+ mHideHandler.sendEmptyMessageDelayed(MSG_HIDE_BUTTON_BAR, 3000);
+ }
+
+ generateButtonBarAnimator(buttonBarHeight,
+ buttonBarHeight - buttonBarMaxHeight, 0, mButtonBarFloatingHeight, 1000);
+ }
+
+ private void hideButtonBar() {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "hideButtonBar");
+ }
+
+ // The desired margin space between the button bar and the bottom of the dialog text
+ final int topMargin = mContext.getResources().getDimensionPixelSize(
+ R.dimen.conf_diag_button_container_top_margin);
+ final int contentHeight = mContent.getHeight() + topMargin;
+ final int screenHeight = mRoot.getHeight();
+ final int buttonBarHeight = mButtonBarContainer.getHeight();
+
+ final int offset = screenHeight + buttonBarHeight
+ - contentHeight + Math.max(mScrollingContainer.getScrollY(), 0);
+ final int translationY = (offset > 0 ?
+ mButtonBarContainer.getHeight() - offset : mButtonBarContainer.getHeight());
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, " topMargin: " + topMargin);
+ Log.d(TAG, " contentHeight: " + contentHeight);
+ Log.d(TAG, " screenHeight: " + screenHeight);
+ Log.d(TAG, " offset: " + offset);
+ Log.d(TAG, " buttonBarHeight: " + buttonBarHeight);
+ Log.d(TAG, " mContent.getPaddingBottom(): " + mContent.getPaddingBottom());
+ Log.d(TAG, " mScrollingContainer.getScrollY(): " + mScrollingContainer.getScrollY());
+ Log.d(TAG, " translationY: " + translationY);
+ }
+
+ if (!mHiddenBefore || mButtonBarAnimator == null) {
+ // Remove previous call to MSG_SHOW_BUTTON_BAR if the user scrolled or something before
+ // the animation got a chance to play
+ mHideHandler.removeMessages(MSG_SHOW_BUTTON_BAR);
+
+ if(mButtonBarAnimator != null) {
+ mButtonBarAnimator.cancel(); // stop current animation if there is one playing
+ }
+
+ // hasn't hidden the bar yet, just hide now to the right height
+ generateButtonBarAnimator(
+ mButtonBarContainer.getTranslationY(), translationY,
+ mButtonBarFloatingHeight, 0, HIDE_ANIM_DURATION);
+ } else if (mButtonBarAnimator.isRunning()) {
+ // we are animating the button bar closing, change to animate to the right place
+ if (Math.abs(mCurrentTranslation - translationY) > 1e-2f) {
+ mButtonBarAnimator.cancel(); // stop current animation
+
+ if (Math.abs(mButtonBarContainer.getTranslationY() - translationY) > 1e-2f) {
+ long duration = Math.max((long) (
+ (float) HIDE_ANIM_DURATION
+ * (translationY - mButtonBarContainer.getTranslationY())
+ / mButtonBarContainer.getHeight()), 0);
+
+ generateButtonBarAnimator(
+ mButtonBarContainer.getTranslationY(), translationY,
+ mButtonBarFloatingHeight, 0, duration);
+ } else {
+ mButtonBarContainer.setTranslationY(translationY);
+ mButtonBarContainer.setTranslationZ(0);
+ }
+ }
+ } else {
+ // not currently animating, have already hidden, snap to the right offset
+ mButtonBarContainer.setTranslationY(translationY);
+ mButtonBarContainer.setTranslationZ(0);
+ }
+
+ mHiddenBefore = true;
+ }
+
+ private void generateButtonBarAnimator(
+ float startY, float endY, float startZ, float endZ, long duration) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "generateButtonBarAnimator");
+ Log.d(TAG, " startY: " + startY);
+ Log.d(TAG, " endY: " + endY);
+ Log.d(TAG, " startZ: " + startZ);
+ Log.d(TAG, " endZ: " + endZ);
+ Log.d(TAG, " duration: " + duration);
+ }
+
+ mButtonBarAnimator =
+ ObjectAnimator.ofPropertyValuesHolder(
+ mButtonBarContainer,
+ PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, startY, endY),
+ PropertyValuesHolder.ofFloat(View.TRANSLATION_Z, startZ, endZ));
+ mCurrentTranslation = endY;
+ mButtonBarAnimator.setDuration(duration);
+ mButtonBarAnimator.setInterpolator(mInterpolator);
+ mButtonBarAnimator.start();
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/wear/TitledSettingsFragment.java b/src/com/android/packageinstaller/permission/ui/wear/TitledSettingsFragment.java
new file mode 100644
index 00000000..ef7efb28
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/wear/TitledSettingsFragment.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.packageinstaller.permission.ui.wear;
+
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v7.widget.RecyclerView;
+import android.support.wearable.view.WearableListView;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import com.android.packageinstaller.permission.ui.wear.settings.ViewUtils;
+import com.android.packageinstaller.R;
+
+/**
+ * Base settings Fragment that shows a title at the top of the page.
+ */
+public abstract class TitledSettingsFragment extends Fragment implements
+ View.OnLayoutChangeListener, WearableListView.ClickListener {
+
+ private static final int ITEM_CHANGE_DURATION_MS = 120;
+
+ private static final String TAG = "TitledSettingsFragment";
+ private int mInitialHeaderHeight;
+
+ protected TextView mHeader;
+ protected WearableListView mWheel;
+
+ private int mCharLimitShortTitle;
+ private int mCharLimitLine;
+ private int mChinOffset;
+
+ private TextWatcher mHeaderTextWatcher = 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 editable) {
+ adjustHeaderSize();
+ }
+ };
+
+ private void adjustHeaderTranslation() {
+ int translation = 0;
+ if (mWheel.getChildCount() > 0) {
+ translation = mWheel.getCentralViewTop() - mWheel.getChildAt(0).getTop();
+ }
+
+ float newTranslation = Math.min(Math.max(-mInitialHeaderHeight, -translation), 0);
+
+ int position = mWheel.getChildAdapterPosition(mWheel.getChildAt(0));
+ if (position == 0 || newTranslation < 0) {
+ mHeader.setTranslationY(newTranslation);
+ }
+ }
+
+ @Override
+ public void onTopEmptyRegionClick() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mCharLimitShortTitle = getResources().getInteger(R.integer.short_title_length);
+ mCharLimitLine = getResources().getInteger(R.integer.char_limit_per_line);
+ }
+
+ @Override
+ public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ if (view == mHeader) {
+ mInitialHeaderHeight = bottom - top;
+ if (ViewUtils.getIsCircular(getContext())) {
+ // We are adding more margin on circular screens, so we need to account for it and use
+ // it for hiding the header.
+ mInitialHeaderHeight +=
+ ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).topMargin;
+ }
+ } else if (view == mWheel) {
+ adjustHeaderTranslation();
+ }
+ }
+
+ protected void initializeLayout(RecyclerView.Adapter adapter) {
+ View v = getView();
+ mWheel = (WearableListView) v.findViewById(R.id.wheel);
+
+ mHeader = (TextView) v.findViewById(R.id.header);
+ mHeader.addOnLayoutChangeListener(this);
+ mHeader.addTextChangedListener(mHeaderTextWatcher);
+
+ mWheel.setAdapter(adapter);
+ mWheel.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+ }
+
+ @Override
+ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+ adjustHeaderTranslation();
+ }
+ });
+ mWheel.setClickListener(this);
+ mWheel.addOnLayoutChangeListener(this);
+
+ // Decrease item change animation duration to approximately half of the default duration.
+ RecyclerView.ItemAnimator itemAnimator = mWheel.getItemAnimator();
+ itemAnimator.setChangeDuration(ITEM_CHANGE_DURATION_MS);
+
+ adjustHeaderSize();
+
+ positionOnCircular(getContext(), mHeader, mWheel);
+ }
+
+ public void positionOnCircular(Context context, View header, final ViewGroup wheel) {
+ if (ViewUtils.getIsCircular(context)) {
+ FrameLayout.LayoutParams params =
+ (FrameLayout.LayoutParams) header.getLayoutParams();
+ params.topMargin = (int) context.getResources().getDimension(
+ R.dimen.settings_header_top_margin_circular);
+ // Note that the margins are made symmetrical here. Since they're symmetrical we choose
+ // the smaller value to maximize usable width.
+ final int margin = (int) Math.min(context.getResources().getDimension(
+ R.dimen.round_content_padding_left), context.getResources().getDimension(
+ R.dimen.round_content_padding_right));
+ params.leftMargin = margin;
+ params.rightMargin = margin;
+ params.gravity = Gravity.CENTER_HORIZONTAL;
+ header.setLayoutParams(params);
+
+ if (header instanceof TextView) {
+ ((TextView) header).setGravity(Gravity.CENTER);
+ }
+
+ final int leftPadding = (int) context.getResources().getDimension(
+ R.dimen.round_content_padding_left);
+ final int rightPadding = (int) context.getResources().getDimension(
+ R.dimen.round_content_padding_right);
+ final int topPadding = (int) context.getResources().getDimension(
+ R.dimen.settings_wearable_list_view_vertical_padding_round);
+ final int bottomPadding = (int) context.getResources().getDimension(
+ R.dimen.settings_wearable_list_view_vertical_padding_round);
+ wheel.setPadding(leftPadding, topPadding, rightPadding, mChinOffset + bottomPadding);
+ wheel.setClipToPadding(false);
+
+ wheel.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
+ @Override
+ public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+ mChinOffset = insets.getSystemWindowInsetBottom();
+ wheel.setPadding(leftPadding, topPadding, rightPadding,
+ mChinOffset + bottomPadding);
+ // This listener is invoked after each time we navigate to SettingsActivity and
+ // it keeps adding padding. We need to disable it after the first update.
+ v.setOnApplyWindowInsetsListener(null);
+ return insets.consumeSystemWindowInsets();
+ }
+ });
+ } else {
+ int leftPadding = (int) context.getResources().getDimension(
+ R.dimen.content_padding_left);
+ wheel.setPadding(leftPadding, wheel.getPaddingTop(), wheel.getPaddingRight(),
+ wheel.getPaddingBottom());
+ }
+ }
+
+ private void adjustHeaderSize() {
+ int length = mHeader.length();
+
+ if (length <= mCharLimitShortTitle) {
+ mHeader.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+ getResources().getDimensionPixelSize(
+ R.dimen.setting_short_header_text_size));
+ } else {
+ mHeader.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+ getResources().getDimensionPixelSize(
+ R.dimen.setting_long_header_text_size));
+ }
+
+ boolean singleLine = length <= mCharLimitLine;
+
+ float height = getResources().getDimension(R.dimen.settings_header_base_height);
+ if (!singleLine) {
+ height += getResources().getDimension(R.dimen.setting_header_extra_line_height);
+ }
+ mHeader.setMinHeight((int) height);
+
+ FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mHeader.getLayoutParams();
+ final Context context = getContext();
+ if (!singleLine) {
+ // Make the top margin a little bit smaller so there is more space for the title.
+ if (ViewUtils.getIsCircular(context)) {
+ params.topMargin = getResources().getDimensionPixelSize(
+ R.dimen.settings_header_top_margin_circular_multiline);
+ } else {
+ params.topMargin = getResources().getDimensionPixelSize(
+ R.dimen.settings_header_top_margin_multiline);
+ }
+ } else {
+ if (ViewUtils.getIsCircular(context)) {
+ params.topMargin = getResources().getDimensionPixelSize(
+ R.dimen.settings_header_top_margin_circular);
+ } else {
+ params.topMargin = getResources().getDimensionPixelSize(
+ R.dimen.settings_header_top_margin);
+ }
+ }
+ mHeader.setLayoutParams(params);
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/wear/WarningConfirmationActivity.java b/src/com/android/packageinstaller/permission/ui/wear/WarningConfirmationActivity.java
new file mode 100644
index 00000000..03713419
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/wear/WarningConfirmationActivity.java
@@ -0,0 +1,118 @@
+/*
+* Copyright (C) 2015 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.android.packageinstaller.permission.ui.wear;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+
+import com.android.packageinstaller.R;
+
+public final class WarningConfirmationActivity extends Activity {
+ public final static String EXTRA_WARNING_MESSAGE = "EXTRA_WARNING_MESSAGE";
+ // Saved index that will be returned in the onActivityResult() callback
+ public final static String EXTRA_INDEX = "EXTRA_INDEX";
+
+ private ConfirmationViewHandler mViewHandler;
+ private String mMessage;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mMessage = getIntent().getStringExtra(EXTRA_WARNING_MESSAGE);
+
+ mViewHandler = new ConfirmationViewHandler(this) {
+ @Override // ConfirmationViewHandler
+ public int getButtonBarMode() {
+ return MODE_VERTICAL_BUTTONS;
+ }
+
+ @Override
+ public void onButton1() {
+ setResultAndFinish(Activity.RESULT_CANCELED);
+ }
+
+ @Override
+ public void onButton2() {
+ setResultAndFinish(Activity.RESULT_OK);
+ }
+
+ @Override
+ public void onButton3() {
+ // no-op
+ }
+
+ @Override
+ public CharSequence getVerticalButton1Text() {
+ return getString(R.string.cancel);
+ }
+
+ @Override
+ public CharSequence getVerticalButton2Text() {
+ return getString(R.string.grant_dialog_button_deny);
+ }
+
+ @Override
+ public CharSequence getVerticalButton3Text() {
+ return null;
+ }
+
+ @Override
+ public Drawable getVerticalButton1Icon() {
+ return getDrawable(R.drawable.cancel_button);
+ }
+
+ @Override
+ public Drawable getVerticalButton2Icon() {
+ return getDrawable(R.drawable.confirm_button);
+ }
+
+ @Override
+ public Drawable getVerticalButton3Icon() {
+ return null;
+ }
+
+ @Override
+ public CharSequence getCurrentPageText() {
+ return null;
+ }
+
+ @Override
+ public Icon getPermissionIcon() {
+ return null;
+ }
+
+ @Override
+ public CharSequence getMessage() {
+ return mMessage;
+ }
+ };
+
+ setContentView(mViewHandler.createView());
+ mViewHandler.invalidate();
+ }
+
+ private void setResultAndFinish(int result) {
+ Intent intent = new Intent();
+ intent.putExtra(EXTRA_INDEX, getIntent().getIntExtra(EXTRA_INDEX, -1));
+ setResult(result, intent);
+ finish();
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/wear/settings/ExtendedOnCenterProximityListener.java b/src/com/android/packageinstaller/permission/ui/wear/settings/ExtendedOnCenterProximityListener.java
new file mode 100644
index 00000000..02c203b3
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/wear/settings/ExtendedOnCenterProximityListener.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.packageinstaller.permission.ui.wear.settings;
+
+import android.support.wearable.view.WearableListView;
+
+public interface ExtendedOnCenterProximityListener
+ extends WearableListView.OnCenterProximityListener {
+ float getProximityMinValue();
+
+ float getProximityMaxValue();
+
+ float getCurrentProximityValue();
+
+ void setScalingAnimatorValue(float value);
+}
diff --git a/src/com/android/packageinstaller/permission/ui/wear/settings/ExtendedViewHolder.java b/src/com/android/packageinstaller/permission/ui/wear/settings/ExtendedViewHolder.java
new file mode 100644
index 00000000..6b725419
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/wear/settings/ExtendedViewHolder.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.packageinstaller.permission.ui.wear.settings;
+
+import android.animation.ObjectAnimator;
+import android.support.wearable.view.WearableListView;
+import android.view.View;
+
+
+public class ExtendedViewHolder extends WearableListView.ViewHolder {
+ public static final long DEFAULT_ANIMATION_DURATION = 150;
+
+ private ObjectAnimator mScalingUpAnimator;
+
+ private ObjectAnimator mScalingDownAnimator;
+
+ private float mMinValue;
+
+ private float mMaxValue;
+
+ public ExtendedViewHolder(View itemView) {
+ super(itemView);
+ if (itemView instanceof ExtendedOnCenterProximityListener) {
+ ExtendedOnCenterProximityListener item =
+ (ExtendedOnCenterProximityListener) itemView;
+ mMinValue = item.getProximityMinValue();
+ item.setScalingAnimatorValue(mMinValue);
+ mMaxValue = item.getProximityMaxValue();
+ mScalingUpAnimator = ObjectAnimator.ofFloat(item, "scalingAnimatorValue", mMinValue,
+ mMaxValue);
+ mScalingUpAnimator.setDuration(DEFAULT_ANIMATION_DURATION);
+ mScalingDownAnimator = ObjectAnimator.ofFloat(item, "scalingAnimatorValue",
+ mMaxValue, mMinValue);
+ mScalingDownAnimator.setDuration(DEFAULT_ANIMATION_DURATION);
+ }
+ }
+
+ public void onCenterProximity(boolean isCentralItem, boolean animate) {
+ if (!(itemView instanceof ExtendedOnCenterProximityListener)) {
+ return;
+ }
+ ExtendedOnCenterProximityListener item = (ExtendedOnCenterProximityListener) itemView;
+ if (isCentralItem) {
+ if (animate) {
+ mScalingDownAnimator.cancel();
+ if (!mScalingUpAnimator.isRunning()) {
+ mScalingUpAnimator.setFloatValues(item.getCurrentProximityValue(),
+ mMaxValue);
+ mScalingUpAnimator.start();
+ }
+ } else {
+ mScalingUpAnimator.cancel();
+ item.setScalingAnimatorValue(item.getProximityMaxValue());
+ }
+ } else {
+ mScalingUpAnimator.cancel();
+ if (animate) {
+ if (!mScalingDownAnimator.isRunning()) {
+ mScalingDownAnimator.setFloatValues(item.getCurrentProximityValue(),
+ mMinValue);
+ mScalingDownAnimator.start();
+ }
+ } else {
+ mScalingDownAnimator.cancel();
+ item.setScalingAnimatorValue(item.getProximityMinValue());
+ }
+ }
+ super.onCenterProximity(isCentralItem, animate);
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/wear/settings/PermissionsSettingsAdapter.java b/src/com/android/packageinstaller/permission/ui/wear/settings/PermissionsSettingsAdapter.java
new file mode 100644
index 00000000..0e0adcbb
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/wear/settings/PermissionsSettingsAdapter.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.packageinstaller.permission.ui.wear.settings;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.support.wearable.view.WearableListView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.model.AppPermissionGroup;
+
+public final class PermissionsSettingsAdapter extends SettingsAdapter<AppPermissionGroup> {
+ private Resources mRes;
+
+ public PermissionsSettingsAdapter(Context context) {
+ super(context, R.layout.permissions_settings_item);
+ mRes = context.getResources();
+ }
+
+ @Override
+ public WearableListView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return new PermissionsViewHolder(new PermissionsSettingsItem(parent.getContext()));
+ }
+
+ @Override
+ public void onBindViewHolder(WearableListView.ViewHolder holder, int position) {
+ super.onBindViewHolder(holder, position);
+ PermissionsViewHolder viewHolder = (PermissionsViewHolder) holder;
+ AppPermissionGroup group = get(position).data;
+
+ if (group.isPolicyFixed()) {
+ viewHolder.imageView.setEnabled(false);
+ viewHolder.textView.setEnabled(false);
+ viewHolder.state.setEnabled(false);
+ viewHolder.state.setText(
+ mRes.getString(R.string.permission_summary_enforced_by_policy));
+ } else {
+ viewHolder.imageView.setEnabled(true);
+ viewHolder.textView.setEnabled(true);
+ viewHolder.state.setEnabled(true);
+
+ if (group.areRuntimePermissionsGranted()) {
+ viewHolder.state.setText(R.string.generic_enabled);
+ } else {
+ viewHolder.state.setText(R.string.generic_disabled);
+ }
+ }
+ }
+
+ private static final class PermissionsViewHolder extends SettingsAdapter.SettingsItemHolder {
+ public final TextView state;
+
+ public PermissionsViewHolder(View view) {
+ super(view);
+ state = (TextView) view.findViewById(R.id.state);
+ }
+ }
+
+ private class PermissionsSettingsItem extends SettingsItem {
+ private final TextView mState;
+ private final float mCenteredAlpha = 1.0f;
+ private final float mNonCenteredAlpha = 0.5f;
+
+ public PermissionsSettingsItem (Context context) {
+ super(context);
+ mState = (TextView) findViewById(R.id.state);
+ }
+
+ @Override
+ public void onCenterPosition(boolean animate) {
+ mImage.setAlpha(mImage.isEnabled() ? mCenteredAlpha : mNonCenteredAlpha);
+ mText.setAlpha(mText.isEnabled() ? mCenteredAlpha : mNonCenteredAlpha);
+ mState.setAlpha(mState.isEnabled() ? mCenteredAlpha : mNonCenteredAlpha);
+ }
+
+ @Override
+ public void onNonCenterPosition(boolean animate) {
+ mImage.setAlpha(mNonCenteredAlpha);
+ mText.setAlpha(mNonCenteredAlpha);
+ mState.setAlpha(mNonCenteredAlpha);
+ }
+ }
+}
+
diff --git a/src/com/android/packageinstaller/permission/ui/wear/settings/SettingsAdapter.java b/src/com/android/packageinstaller/permission/ui/wear/settings/SettingsAdapter.java
new file mode 100644
index 00000000..baf1a2b4
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/wear/settings/SettingsAdapter.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.packageinstaller.permission.ui.wear.settings;
+
+import android.content.Context;
+import android.support.wearable.view.CircledImageView;
+import android.support.wearable.view.WearableListView;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import com.android.packageinstaller.R;
+
+import java.util.ArrayList;
+
+/**
+ * Common adapter for settings views. Maintains a list of 'Settings', consisting of a name,
+ * icon and optional activity-specific data.
+ */
+public class SettingsAdapter<T> extends WearableListView.Adapter {
+ private static final String TAG = "SettingsAdapter";
+ private final Context mContext;
+
+ public static final class Setting<S> {
+ public static final int ID_INVALID = -1;
+
+ public final int id;
+ public int nameResourceId;
+ public CharSequence name;
+ public int iconResource;
+ public boolean inProgress;
+ public S data;
+
+ public Setting(CharSequence name, int iconResource, S data) {
+ this(name, iconResource, data, ID_INVALID);
+ }
+
+ public Setting(CharSequence name, int iconResource, S data, int id) {
+ this.name = name;
+ this.iconResource = iconResource;
+ this.data = data;
+ this.inProgress = false;
+ this.id = id;
+ }
+
+ public Setting(int nameResource, int iconResource, S data, int id) {
+ this.nameResourceId = nameResource;
+ this.iconResource = iconResource;
+ this.data = data;
+ this.inProgress = false;
+ this.id = id;
+ }
+
+ public Setting(int nameResource, int iconResource, int id) {
+ this.nameResourceId = nameResource;
+ this.iconResource = iconResource;
+ this.data = null;
+ this.inProgress = false;
+ this.id = id;
+ }
+
+ public Setting(CharSequence name, int iconResource, int id) {
+ this(name, iconResource, null, id);
+ }
+
+ }
+
+ private final int mItemLayoutId;
+ private final float mDefaultCircleRadiusPercent;
+ private final float mSelectedCircleRadiusPercent;
+
+ protected ArrayList<Setting<T>> mSettings = new ArrayList<Setting<T>>();
+
+ public SettingsAdapter(Context context, int itemLayoutId) {
+ mContext = context;
+ mItemLayoutId = itemLayoutId;
+ mDefaultCircleRadiusPercent = context.getResources().getFraction(
+ R.dimen.default_settings_circle_radius_percent, 1, 1);
+ mSelectedCircleRadiusPercent = context.getResources().getFraction(
+ R.dimen.selected_settings_circle_radius_percent, 1, 1);
+ }
+
+ @Override
+ public WearableListView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return new SettingsItemHolder(new SettingsItem(parent.getContext()));
+ }
+
+ @Override
+ public void onBindViewHolder(WearableListView.ViewHolder holder, int position) {
+ Setting<T> setting = mSettings.get(position);
+ if (setting.iconResource == -1) {
+ ((SettingsItemHolder) holder).imageView.setVisibility(View.GONE);
+ } else {
+ ((SettingsItemHolder) holder).imageView.setVisibility(View.VISIBLE);
+ ((SettingsItemHolder) holder).imageView.setImageResource(
+ mSettings.get(position).iconResource);
+ }
+ Log.d(TAG, "onBindViewHolder " + setting.name + " " + setting.id + " " + setting
+ .nameResourceId);
+ if (setting.name == null && setting.nameResourceId != 0) {
+ setting.name = mContext.getString(setting.nameResourceId);
+ }
+ ((SettingsItemHolder) holder).textView.setText(setting.name);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mSettings.size();
+ }
+
+ public void addSetting(CharSequence name, int iconResource) {
+ addSetting(name, iconResource, null);
+ }
+
+ public void addSetting(CharSequence name, int iconResource, T intent) {
+ addSetting(mSettings.size(), name, iconResource, intent);
+ }
+
+ public void addSetting(int index, CharSequence name, int iconResource, T intent) {
+ addSetting(Setting.ID_INVALID, index, name, iconResource, intent);
+ }
+
+ public void addSetting(int id, int index, CharSequence name, int iconResource, T intent) {
+ mSettings.add(index, new Setting<T>(name, iconResource, intent, id));
+ notifyItemInserted(index);
+ }
+
+ public void addSettingDontNotify(Setting<T> setting) {
+ mSettings.add(setting);
+ }
+
+ public void addSetting(Setting<T> setting) {
+ mSettings.add(setting);
+ notifyItemInserted(mSettings.size() - 1);
+ }
+
+ public void addSetting(int index, Setting<T> setting) {
+ mSettings.add(index, setting);
+ notifyItemInserted(index);
+ }
+
+ /**
+ * Returns the index of the setting in the adapter based on the ID supplied when it was
+ * originally added.
+ * @param id the setting's id
+ * @return index in the adapter of the setting. -1 if not found.
+ */
+ public int findSetting(int id) {
+ for (int i = mSettings.size() - 1; i >= 0; --i) {
+ Setting setting = mSettings.get(i);
+
+ if (setting.id == id) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Removes a setting at the given index.
+ * @param index the index of the setting to be removed
+ */
+ public void removeSetting(int index) {
+ mSettings.remove(index);
+ notifyDataSetChanged();
+ }
+
+ public void clearSettings() {
+ mSettings.clear();
+ notifyDataSetChanged();
+ }
+
+ /**
+ * Updates a setting in place.
+ * @param index the index of the setting
+ * @param name the updated setting name
+ * @param iconResource the update setting icon
+ * @param intent the updated intent for the setting
+ */
+ public void updateSetting(int index, CharSequence name, int iconResource, T intent) {
+ Setting<T> setting = mSettings.get(index);
+ setting.iconResource = iconResource;
+ setting.name = name;
+ setting.data = intent;
+ notifyItemChanged(index);
+ }
+
+ public Setting<T> get(int position) {
+ return mSettings.get(position);
+ }
+
+ protected static class SettingsItemHolder extends ExtendedViewHolder {
+ public final CircledImageView imageView;
+ public final TextView textView;
+
+ public SettingsItemHolder(View itemView) {
+ super(itemView);
+
+ imageView = ((CircledImageView) itemView.findViewById(R.id.image));
+ textView = ((TextView) itemView.findViewById(R.id.text));
+ }
+ }
+
+ protected class SettingsItem extends FrameLayout implements ExtendedOnCenterProximityListener {
+
+ protected final CircledImageView mImage;
+ protected final TextView mText;
+
+ public SettingsItem(Context context) {
+ super(context);
+ View view = View.inflate(context, mItemLayoutId, null);
+ FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT);
+ params.gravity = Gravity.CENTER_VERTICAL;
+ addView(view, params);
+ mImage = (CircledImageView) findViewById(R.id.image);
+ mText = (TextView) findViewById(R.id.text);
+ }
+
+ @Override
+ public float getProximityMinValue() {
+ return mDefaultCircleRadiusPercent;
+ }
+
+ @Override
+ public float getProximityMaxValue() {
+ return mSelectedCircleRadiusPercent;
+ }
+
+ @Override
+ public float getCurrentProximityValue() {
+ return mImage.getCircleRadiusPressedPercent();
+ }
+
+ @Override
+ public void setScalingAnimatorValue(float value) {
+ mImage.setCircleRadiusPercent(value);
+ mImage.setCircleRadiusPressedPercent(value);
+ }
+
+ @Override
+ public void onCenterPosition(boolean animate) {
+ mImage.setAlpha(1f);
+ mText.setAlpha(1f);
+ }
+
+ @Override
+ public void onNonCenterPosition(boolean animate) {
+ mImage.setAlpha(0.5f);
+ mText.setAlpha(0.5f);
+ }
+
+ TextView getTextView() {
+ return mText;
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/wear/settings/ViewUtils.java b/src/com/android/packageinstaller/permission/ui/wear/settings/ViewUtils.java
new file mode 100644
index 00000000..cf1c0fd0
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/wear/settings/ViewUtils.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.packageinstaller.permission.ui.wear.settings;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Utility to determine screen shape
+ */
+public class ViewUtils {
+
+ public static boolean getIsCircular(Context context) {
+ return context.getResources().getConfiguration().isScreenRound();
+ }
+
+ /**
+ * Set the given {@code view} and all descendants to the given {@code enabled} state.
+ *
+ * @param view the parent view of a subtree of components whose enabled state must be set
+ * @param enabled the new enabled state of the subtree of components
+ */
+ public static void setEnabled(View view, boolean enabled) {
+ view.setEnabled(enabled);
+
+ if (view instanceof ViewGroup) {
+ final ViewGroup viewGroup = (ViewGroup) view;
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ setEnabled(viewGroup.getChildAt(i), enabled);
+ }
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/utils/Utils.java b/src/com/android/packageinstaller/permission/utils/Utils.java
index 2940a729..b8a79d54 100644
--- a/src/com/android/packageinstaller/permission/utils/Utils.java
+++ b/src/com/android/packageinstaller/permission/utils/Utils.java
@@ -31,8 +31,11 @@ import android.util.Log;
import android.util.TypedValue;
import com.android.packageinstaller.permission.model.AppPermissionGroup;
+import com.android.packageinstaller.permission.model.AppPermissions;
import com.android.packageinstaller.permission.model.PermissionApps.PermissionApp;
+import java.util.List;
+
public class Utils {
private static final String LOG_TAG = "Utils";
@@ -127,14 +130,24 @@ public class Utils {
return launcherPkgs;
}
+ public static List<ApplicationInfo> getAllInstalledApplications(Context context) {
+ return context.getPackageManager().getInstalledApplications(0);
+ }
+
public static boolean isSystem(PermissionApp app, ArraySet<String> launcherPkgs) {
- ApplicationInfo info = app.getAppInfo();
+ return isSystem(app.getAppInfo(), launcherPkgs);
+ }
+
+ public static boolean isSystem(AppPermissions app, ArraySet<String> launcherPkgs) {
+ return isSystem(app.getPackageInfo().applicationInfo, launcherPkgs);
+ }
+
+ public static boolean isSystem(ApplicationInfo info, ArraySet<String> launcherPkgs) {
return info.isSystemApp() && (info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0
&& !launcherPkgs.contains(info.packageName);
}
- public static boolean isTelevision(Context context) {
- int uiMode = context.getResources().getConfiguration().uiMode;
- return (uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION;
+ public static boolean isTelevision(Object o) {
+ return false;
}
}
diff --git a/src/com/android/packageinstaller/wear/WearPackageArgs.java b/src/com/android/packageinstaller/wear/WearPackageArgs.java
new file mode 100644
index 00000000..67051da0
--- /dev/null
+++ b/src/com/android/packageinstaller/wear/WearPackageArgs.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.packageinstaller.wear;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * Installation Util that contains a list of parameters that are needed for
+ * installing/uninstalling.
+ */
+public class WearPackageArgs {
+ private static final String KEY_ASSET_URI =
+ "com.google.android.clockwork.EXTRA_ASSET_URI";
+ private static final String KEY_START_ID =
+ "com.google.android.clockwork.EXTRA_START_ID";
+ private static final String KEY_PERM_URI =
+ "com.google.android.clockwork.EXTRA_PERM_URI";
+ private static final String KEY_CHECK_PERMS =
+ "com.google.android.clockwork.EXTRA_CHECK_PERMS";
+ private static final String KEY_SKIP_IF_SAME_VERSION =
+ "com.google.android.clockwork.EXTRA_SKIP_IF_SAME_VERSION";
+ private static final String KEY_COMPRESSION_ALG =
+ "com.google.android.clockwork.EXTRA_KEY_COMPRESSION_ALG";
+ private static final String KEY_COMPANION_SDK_VERSION =
+ "com.google.android.clockwork.EXTRA_KEY_COMPANION_SDK_VERSION";
+ private static final String KEY_COMPANION_DEVICE_VERSION =
+ "com.google.android.clockwork.EXTRA_KEY_COMPANION_DEVICE_VERSION";
+ private static final String KEY_SHOULD_CHECK_GMS_DEPENDENCY =
+ "com.google.android.clockwork.EXTRA_KEY_SHOULD_CHECK_GMS_DEPENDENCY";
+
+ public static String getPackageName(Bundle b) {
+ return b.getString(Intent.EXTRA_INSTALLER_PACKAGE_NAME);
+ }
+
+ public static Uri getAssetUri(Bundle b) {
+ return b.getParcelable(KEY_ASSET_URI);
+ }
+
+ public static Bundle setAssetUri(Bundle b, Uri assetUri) {
+ b.putParcelable(KEY_ASSET_URI, assetUri);
+ return b;
+ }
+
+ public static Uri getPermUri(Bundle b) {
+ return b.getParcelable(KEY_PERM_URI);
+ }
+
+ public static boolean checkPerms(Bundle b) {
+ return b.getBoolean(KEY_CHECK_PERMS);
+ }
+
+ public static boolean skipIfSameVersion(Bundle b) {
+ return b.getBoolean(KEY_SKIP_IF_SAME_VERSION);
+ }
+
+ public static int getCompanionSdkVersion(Bundle b) {
+ return b.getInt(KEY_COMPANION_SDK_VERSION);
+ }
+
+ public static int getCompanionDeviceVersion(Bundle b) {
+ return b.getInt(KEY_COMPANION_DEVICE_VERSION);
+ }
+
+ public static String getCompressionAlg(Bundle b) {
+ return b.getString(KEY_COMPRESSION_ALG);
+ }
+
+ public static int getStartId(Bundle b) {
+ return b.getInt(KEY_START_ID);
+ }
+
+ public static Bundle setStartId(Bundle b, int startId) {
+ b.putInt(KEY_START_ID, startId);
+ return b;
+ }
+}
diff --git a/src/com/android/packageinstaller/wear/WearPackageIconProvider.java b/src/com/android/packageinstaller/wear/WearPackageIconProvider.java
new file mode 100644
index 00000000..02b9d298
--- /dev/null
+++ b/src/com/android/packageinstaller/wear/WearPackageIconProvider.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.packageinstaller.wear;
+
+import android.annotation.TargetApi;
+import android.app.ActivityManager;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Build;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.List;
+
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+public class WearPackageIconProvider extends ContentProvider {
+ private static final String TAG = "WearPackageIconProvider";
+ public static final String AUTHORITY = "com.google.android.packageinstaller.wear.provider";
+
+ private static final String REQUIRED_PERMISSION =
+ "com.google.android.permission.INSTALL_WEARABLE_PACKAGES";
+
+ /** MIME types. */
+ public static final String ICON_TYPE = "vnd.android.cursor.item/cw_package_icon";
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ throw new UnsupportedOperationException("Query is not supported.");
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ if (uri == null) {
+ throw new IllegalArgumentException("URI passed in is null.");
+ }
+
+ if (AUTHORITY.equals(uri.getEncodedAuthority())) {
+ return ICON_TYPE;
+ }
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException("Insert is not supported.");
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ if (uri == null) {
+ throw new IllegalArgumentException("URI passed in is null.");
+ }
+
+ enforcePermissions(uri);
+
+ if (ICON_TYPE.equals(getType(uri))) {
+ final File file = WearPackageUtil.getIconFile(
+ this.getContext().getApplicationContext(), getPackageNameFromUri(uri));
+ if (file != null) {
+ file.delete();
+ }
+ }
+
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException("Update is not supported.");
+ }
+
+ @Override
+ public ParcelFileDescriptor openFile(
+ Uri uri, @SuppressWarnings("unused") String mode) throws FileNotFoundException {
+ if (uri == null) {
+ throw new IllegalArgumentException("URI passed in is null.");
+ }
+
+ enforcePermissions(uri);
+
+ if (ICON_TYPE.equals(getType(uri))) {
+ final File file = WearPackageUtil.getIconFile(
+ this.getContext().getApplicationContext(), getPackageNameFromUri(uri));
+ if (file != null) {
+ return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+ }
+ }
+ return null;
+ }
+
+ public static Uri getUriForPackage(final String packageName) {
+ return Uri.parse("content://" + AUTHORITY + "/icons/" + packageName + ".icon");
+ }
+
+ private String getPackageNameFromUri(Uri uri) {
+ if (uri == null) {
+ return null;
+ }
+ List<String> pathSegments = uri.getPathSegments();
+ String packageName = pathSegments.get(pathSegments.size() - 1);
+
+ if (packageName.endsWith(".icon")) {
+ packageName = packageName.substring(0, packageName.lastIndexOf("."));
+ }
+ return packageName;
+ }
+
+ /**
+ * Make sure the calling app is either a system app or the same app or has the right permission.
+ * @throws SecurityException if the caller has insufficient permissions.
+ */
+ @TargetApi(Build.VERSION_CODES.BASE_1_1)
+ private void enforcePermissions(Uri uri) {
+ // Redo some of the permission check in {@link ContentProvider}. Just add an extra check to
+ // allow System process to access this provider.
+ Context context = getContext();
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final int myUid = android.os.Process.myUid();
+
+ if (uid == myUid || isSystemApp(context, pid)) {
+ return;
+ }
+
+ if (context.checkPermission(REQUIRED_PERMISSION, pid, uid) == PERMISSION_GRANTED) {
+ return;
+ }
+
+ // last chance, check against any uri grants
+ if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ == PERMISSION_GRANTED) {
+ return;
+ }
+
+ throw new SecurityException("Permission Denial: reading "
+ + getClass().getName() + " uri " + uri + " from pid=" + pid
+ + ", uid=" + uid);
+ }
+
+ /**
+ * From the pid of the calling process, figure out whether this is a system app or not. We do
+ * this by checking the application information corresponding to the pid and then checking if
+ * FLAG_SYSTEM is set.
+ */
+ @TargetApi(Build.VERSION_CODES.CUPCAKE)
+ private boolean isSystemApp(Context context, int pid) {
+ // Get the Activity Manager Object
+ ActivityManager aManager =
+ (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ // Get the list of running Applications
+ List<ActivityManager.RunningAppProcessInfo> rapInfoList =
+ aManager.getRunningAppProcesses();
+ for (ActivityManager.RunningAppProcessInfo rapInfo : rapInfoList) {
+ if (rapInfo.pid == pid) {
+ try {
+ PackageInfo pkgInfo = context.getPackageManager().getPackageInfo(
+ rapInfo.pkgList[0], 0);
+ if (pkgInfo != null && pkgInfo.applicationInfo != null &&
+ (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ Log.d(TAG, pid + " is a system app.");
+ return true;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Could not find package information.", e);
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/com/android/packageinstaller/wear/WearPackageInstallerService.java b/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
new file mode 100644
index 00000000..3874c0a4
--- /dev/null
+++ b/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.packageinstaller.wear;
+
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.FeatureInfo;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageInstallObserver;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
+import android.os.Process;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.packageinstaller.DeviceUtils;
+import com.android.packageinstaller.PackageUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Service that will install/uninstall packages. It will check for permissions and features as well.
+ *
+ * -----------
+ *
+ * Debugging information:
+ *
+ * Install Action example:
+ * adb shell am startservice -a com.android.packageinstaller.wear.INSTALL_PACKAGE \
+ * -t vnd.android.cursor.item/wearable_apk \
+ * -d content://com.google.android.clockwork.home.provider/host/com.google.android.wearable.app/wearable/com.google.android.gms/apk \
+ * --es android.intent.extra.INSTALLER_PACKAGE_NAME com.google.android.gms \
+ * --ez com.google.android.clockwork.EXTRA_CHECK_PERMS false \
+ * --eu com.google.android.clockwork.EXTRA_PERM_URI content://com.google.android.clockwork.home.provider/host/com.google.android.wearable.app/permissions \
+ * com.android.packageinstaller/com.android.packageinstaller.wear.WearPackageInstallerService
+ *
+ * Retry GMS:
+ * adb shell am startservice -a com.android.packageinstaller.wear.RETRY_GMS \
+ * com.android.packageinstaller/com.android.packageinstaller.wear.WearPackageInstallerService
+ */
+public class WearPackageInstallerService extends Service {
+ private static final String TAG = "WearPkgInstallerService";
+
+ private static final String KEY_PACKAGE_NAME =
+ "com.google.android.clockwork.EXTRA_PACKAGE_NAME";
+ private static final String KEY_APP_LABEL = "com.google.android.clockwork.EXTRA_APP_LABEL";
+ private static final String KEY_APP_ICON_URI =
+ "com.google.android.clockwork.EXTRA_APP_ICON_URI";
+ private static final String KEY_PERMS_LIST = "com.google.android.clockwork.EXTRA_PERMS_LIST";
+ private static final String KEY_HAS_LAUNCHER =
+ "com.google.android.clockwork.EXTRA_HAS_LAUNCHER";
+
+ private static final String HOME_APP_PACKAGE_NAME = "com.google.android.wearable.app";
+ private static final String SHOW_PERMS_SERVICE_CLASS =
+ "com.google.android.clockwork.packagemanager.ShowPermsService";
+
+ /**
+ * Normally sent by the Play store (See http://go/playstore-gms_updated), we instead
+ * broadcast, ourselves. http://b/17387718
+ */
+ private static final String GMS_UPDATED_BROADCAST = "com.google.android.gms.GMS_UPDATED";
+ public static final String GMS_PACKAGE_NAME = "com.google.android.gms";
+
+ private final int START_INSTALL = 1;
+ private final int START_UNINSTALL = 2;
+
+ private final class ServiceHandler extends Handler {
+ public ServiceHandler(Looper looper) {
+ super(looper);
+ }
+
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case START_INSTALL:
+ installPackage(msg.getData());
+ break;
+ case START_UNINSTALL:
+ uninstallPackage(msg.getData());
+ break;
+ }
+ }
+ }
+ private ServiceHandler mServiceHandler;
+
+ private static volatile PowerManager.WakeLock lockStatic = null;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ HandlerThread thread = new HandlerThread("PackageInstallerThread",
+ Process.THREAD_PRIORITY_BACKGROUND);
+ thread.start();
+
+ mServiceHandler = new ServiceHandler(thread.getLooper());
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (!DeviceUtils.isWear(this)) {
+ Log.w(TAG, "Not running on wearable");
+ return START_NOT_STICKY;
+ }
+ PowerManager.WakeLock lock = getLock(this.getApplicationContext());
+ if (!lock.isHeld()) {
+ lock.acquire();
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Got install/uninstall request " + intent);
+ }
+ if (intent != null) {
+ Bundle intentBundle = intent.getExtras();
+ WearPackageArgs.setStartId(intentBundle, startId);
+ if (Intent.ACTION_INSTALL_PACKAGE.equals(intent.getAction())) {
+ final Message msg = mServiceHandler.obtainMessage(START_INSTALL);
+ WearPackageArgs.setAssetUri(intentBundle, intent.getData());
+ msg.setData(intentBundle);
+ mServiceHandler.sendMessage(msg);
+ } else if (Intent.ACTION_UNINSTALL_PACKAGE.equals(intent.getAction())) {
+ Message msg = mServiceHandler.obtainMessage(START_UNINSTALL);
+ msg.setData(intentBundle);
+ mServiceHandler.sendMessage(msg);
+ }
+ }
+ return START_NOT_STICKY;
+ }
+
+ private void installPackage(Bundle argsBundle) {
+ int startId = WearPackageArgs.getStartId(argsBundle);
+ final String packageName = WearPackageArgs.getPackageName(argsBundle);
+ final Uri assetUri = WearPackageArgs.getAssetUri(argsBundle);
+ final Uri permUri = WearPackageArgs.getPermUri(argsBundle);
+ boolean checkPerms = WearPackageArgs.checkPerms(argsBundle);
+ boolean skipIfSameVersion = WearPackageArgs.skipIfSameVersion(argsBundle);
+ int companionSdkVersion = WearPackageArgs.getCompanionSdkVersion(argsBundle);
+ int companionDeviceVersion = WearPackageArgs.getCompanionDeviceVersion(argsBundle);
+ String compressionAlg = WearPackageArgs.getCompressionAlg(argsBundle);
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Installing package: " + packageName + ", assetUri: " + assetUri +
+ ",permUri: " + permUri + ", startId: " + startId + ", checkPerms: " +
+ checkPerms + ", skipIfSameVersion: " + skipIfSameVersion +
+ ", compressionAlg: " + compressionAlg + ", companionSdkVersion: " +
+ companionSdkVersion + ", companionDeviceVersion: " + companionDeviceVersion);
+ }
+ final PackageManager pm = getPackageManager();
+ File tempFile = null;
+ int installFlags = 0;
+ PowerManager.WakeLock lock = getLock(this.getApplicationContext());
+ boolean messageSent = false;
+ try {
+ PackageInfo existingPkgInfo = null;
+ try {
+ existingPkgInfo = pm.getPackageInfo(packageName,
+ PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS);
+ if(existingPkgInfo != null) {
+ installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // Ignore this exception. We could not find the package, will treat as a new
+ // installation.
+ }
+ if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Replacing package:" + packageName);
+ }
+ }
+ ParcelFileDescriptor parcelFd = getContentResolver()
+ .openFileDescriptor(assetUri, "r");
+ tempFile = WearPackageUtil.getFileFromFd(WearPackageInstallerService.this,
+ parcelFd, packageName, compressionAlg);
+ if (tempFile == null) {
+ Log.e(TAG, "Could not create a temp file from FD for " + packageName);
+ return;
+ }
+ PackageParser.Package pkg = PackageUtil.getPackageInfo(tempFile);
+ if (pkg == null) {
+ Log.e(TAG, "Could not parse apk information for " + packageName);
+ return;
+ }
+
+ if (!pkg.packageName.equals(packageName)) {
+ Log.e(TAG, "Wearable Package Name has to match what is provided for " +
+ packageName);
+ return;
+ }
+
+ List<String> wearablePerms = pkg.requestedPermissions;
+
+ // Log if the installed pkg has a higher version number.
+ if (existingPkgInfo != null) {
+ if (existingPkgInfo.versionCode == pkg.mVersionCode) {
+ if (skipIfSameVersion) {
+ Log.w(TAG, "Version number (" + pkg.mVersionCode +
+ ") of new app is equal to existing app for " + packageName +
+ "; not installing due to versionCheck");
+ return;
+ } else {
+ Log.w(TAG, "Version number of new app (" + pkg.mVersionCode +
+ ") is equal to existing app for " + packageName);
+ }
+ } else if (existingPkgInfo.versionCode > pkg.mVersionCode) {
+ Log.w(TAG, "Version number of new app (" + pkg.mVersionCode +
+ ") is lower than existing app ( " + existingPkgInfo.versionCode +
+ ") for " + packageName);
+ }
+
+ // Following the Android Phone model, we should only check for permissions for any
+ // newly defined perms.
+ if (existingPkgInfo.requestedPermissions != null) {
+ for (int i = 0; i < existingPkgInfo.requestedPermissions.length; ++i) {
+ // If the permission is granted, then we will not ask to request it again.
+ if ((existingPkgInfo.requestedPermissionsFlags[i] &
+ PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, existingPkgInfo.requestedPermissions[i] +
+ " is already granted for " + packageName);
+ }
+ wearablePerms.remove(existingPkgInfo.requestedPermissions[i]);
+ }
+ }
+ }
+ }
+
+ // Check permissions on both the new wearable package and also on the already installed
+ // wearable package.
+ // If the app is targeting API level 23, we will also start a service in ClockworkHome
+ // which will ultimately prompt the user to accept/reject permissions.
+ if (checkPerms && !checkPermissions(pkg, companionSdkVersion, companionDeviceVersion,
+ permUri, wearablePerms, tempFile)) {
+ Log.w(TAG, "Wearable does not have enough permissions.");
+ return;
+ }
+
+ // Check that the wearable has all the features.
+ boolean hasAllFeatures = true;
+ if (pkg.reqFeatures != null) {
+ for (FeatureInfo feature : pkg.reqFeatures) {
+ if (feature.name != null && !pm.hasSystemFeature(feature.name) &&
+ (feature.flags & FeatureInfo.FLAG_REQUIRED) != 0) {
+ Log.e(TAG, "Wearable does not have required feature: " + feature +
+ " for " + packageName);
+ hasAllFeatures = false;
+ }
+ }
+ }
+
+ if (!hasAllFeatures) {
+ return;
+ }
+
+ // Finally install the package.
+ pm.installPackage(Uri.fromFile(tempFile),
+ new PackageInstallObserver(this, lock, startId, packageName),
+ installFlags, packageName);
+
+ messageSent = true;
+ Log.i(TAG, "Sent installation request for " + packageName);
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "Could not find the file with URI " + assetUri, e);
+ } finally {
+ if (!messageSent) {
+ // Some error happened. If the message has been sent, we can wait for the observer
+ // which will finish the service.
+ if (tempFile != null) {
+ tempFile.delete();
+ }
+ finishService(lock, startId);
+ }
+ }
+ }
+
+ private void uninstallPackage(Bundle argsBundle) {
+ int startId = WearPackageArgs.getStartId(argsBundle);
+ final String packageName = WearPackageArgs.getPackageName(argsBundle);
+
+ final PackageManager pm = getPackageManager();
+ PowerManager.WakeLock lock = getLock(this.getApplicationContext());
+ pm.deletePackage(packageName, new PackageDeleteObserver(lock, startId),
+ PackageManager.DELETE_ALL_USERS);
+ startPermsServiceForUninstall(packageName);
+ Log.i(TAG, "Sent delete request for " + packageName);
+ }
+
+ private boolean checkPermissions(PackageParser.Package pkg, int companionSdkVersion,
+ int companionDeviceVersion, Uri permUri, List<String> wearablePermissions,
+ File apkFile) {
+ // If the Wear App is targeted for M-release, since the permission model has been changed,
+ // permissions may not be granted on the phone yet. We need a different flow for user to
+ // accept these permissions.
+ //
+ // Assumption: Code is running on E-release, so Wear is always running M.
+ // - Case 1: If the Wear App(WA) is targeting 23, always choose the M model (4 cases)
+ // - Case 2: Else if the Phone App(PA) is targeting 23 and Phone App(P) is running on M,
+ // show a Dialog so that the user can accept all perms (1 case)
+ // - Also show a warning to the developer if the watch is targeting M
+ // - Case 3: If Case 2 is false, then the behavior on the phone is pre-M. Stick to pre-M
+ // behavior on watch (as long as we don't hit case 1).
+ // - 3a: WA(22) PA(22) P(22) -> watch app is not targeting 23
+ // - 3b: WA(22) PA(22) P(23) -> watch app is not targeting 23
+ // - 3c: WA(22) PA(23) P(22) -> watch app is not targeting 23
+ // - Case 4: We did not get Companion App's/Device's version, always show dialog to user to
+ // accept permissions. (This happens if the AndroidWear Companion App is really old).
+ boolean isWearTargetingM =
+ pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
+ if (isWearTargetingM) { // Case 1
+ // Install the app if Wear App is ready for the new perms model.
+ return true;
+ }
+
+ List<String> unavailableWearablePerms = getWearPermsNotGrantedOnPhone(pkg.packageName,
+ permUri, wearablePermissions);
+ if (unavailableWearablePerms == null) {
+ return false;
+ }
+
+ if (unavailableWearablePerms.size() == 0) {
+ // All permissions requested by the watch are already granted on the phone, no need
+ // to do anything.
+ return true;
+ }
+
+ // Cases 2 and 4.
+ boolean isCompanionTargetingM = companionSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
+ boolean isCompanionRunningM = companionDeviceVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
+ if (isCompanionTargetingM) { // Case 2 Warning
+ Log.w(TAG, "MNC: Wear app's targetSdkVersion should be at least 23, if " +
+ "phone app is targeting at least 23, will continue.");
+ }
+ if ((isCompanionTargetingM && isCompanionRunningM) || // Case 2
+ companionSdkVersion == 0 || companionDeviceVersion == 0) { // Case 4
+ startPermsServiceForInstall(pkg, apkFile, unavailableWearablePerms);
+ }
+
+ // Case 3a-3c.
+ return false;
+ }
+
+ /**
+ * Given a {@string packageName} corresponding to a phone app, query the provider for all the
+ * perms that are granted.
+ * @return null if there is an error retrieving this info
+ * else, a list of all the wearable perms that are not in the list of granted perms of
+ * the phone.
+ */
+ private List<String> getWearPermsNotGrantedOnPhone(String packageName, Uri permUri,
+ List<String> wearablePermissions) {
+ if (permUri == null) {
+ Log.e(TAG, "Permission URI is null");
+ return null;
+ }
+ Cursor permCursor = getContentResolver().query(permUri, null, null, null, null);
+ if (permCursor == null) {
+ Log.e(TAG, "Could not get the cursor for the permissions");
+ return null;
+ }
+
+ Set<String> grantedPerms = new HashSet<>();
+ Set<String> ungrantedPerms = new HashSet<>();
+ while(permCursor.moveToNext()) {
+ // Make sure that the MatrixCursor returned by the ContentProvider has 2 columns and
+ // verify their types.
+ if (permCursor.getColumnCount() == 2
+ && Cursor.FIELD_TYPE_STRING == permCursor.getType(0)
+ && Cursor.FIELD_TYPE_INTEGER == permCursor.getType(1)) {
+ String perm = permCursor.getString(0);
+ Integer granted = permCursor.getInt(1);
+ if (granted == 1) {
+ grantedPerms.add(perm);
+ } else {
+ ungrantedPerms.add(perm);
+ }
+ }
+ }
+ permCursor.close();
+
+ ArrayList<String> unavailableWearablePerms = new ArrayList<>();
+ for (String wearablePerm : wearablePermissions) {
+ if (!grantedPerms.contains(wearablePerm)) {
+ unavailableWearablePerms.add(wearablePerm);
+ if (!ungrantedPerms.contains(wearablePerm)) {
+ // This is an error condition. This means that the wearable has permissions that
+ // are not even declared in its host app. This is a developer error.
+ Log.e(TAG, "Wearable " + packageName + " has a permission \"" + wearablePerm
+ + "\" that is not defined in the host application's manifest.");
+ } else {
+ Log.w(TAG, "Wearable " + packageName + " has a permission \"" + wearablePerm +
+ "\" that is not granted in the host application.");
+ }
+ }
+ }
+ return unavailableWearablePerms;
+ }
+
+ private void finishService(PowerManager.WakeLock lock, int startId) {
+ if (lock.isHeld()) {
+ lock.release();
+ }
+ stopSelf(startId);
+ }
+
+ private synchronized PowerManager.WakeLock getLock(Context context) {
+ if (lockStatic == null) {
+ PowerManager mgr =
+ (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ lockStatic = mgr.newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, context.getClass().getSimpleName());
+ lockStatic.setReferenceCounted(true);
+ }
+ return lockStatic;
+ }
+
+ private void startPermsServiceForInstall(final PackageParser.Package pkg, final File apkFile,
+ List<String> unavailableWearablePerms) {
+ final String packageName = pkg.packageName;
+
+ Intent showPermsIntent = new Intent()
+ .setComponent(new ComponentName(HOME_APP_PACKAGE_NAME, SHOW_PERMS_SERVICE_CLASS))
+ .setAction(Intent.ACTION_INSTALL_PACKAGE);
+ final PackageManager pm = getPackageManager();
+ pkg.applicationInfo.publicSourceDir = apkFile.getPath();
+ final CharSequence label = pkg.applicationInfo.loadLabel(pm);
+ final Uri iconUri = getIconFileUri(packageName, pkg.applicationInfo.loadIcon(pm));
+ if (TextUtils.isEmpty(label) || iconUri == null) {
+ Log.e(TAG, "MNC: Could not launch service since either label " + label +
+ ", or icon Uri " + iconUri + " is invalid.");
+ } else {
+ showPermsIntent.putExtra(KEY_APP_LABEL, label);
+ showPermsIntent.putExtra(KEY_APP_ICON_URI, iconUri);
+ showPermsIntent.putExtra(KEY_PACKAGE_NAME, packageName);
+ showPermsIntent.putExtra(KEY_PERMS_LIST,
+ unavailableWearablePerms.toArray(new String[0]));
+ showPermsIntent.putExtra(KEY_HAS_LAUNCHER, WearPackageUtil.hasLauncherActivity(pkg));
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "MNC: Launching Intent " + showPermsIntent + " for " + packageName +
+ " with name " + label);
+ }
+ startService(showPermsIntent);
+ }
+ }
+
+ private void startPermsServiceForUninstall(final String packageName) {
+ Intent showPermsIntent = new Intent()
+ .setComponent(new ComponentName(HOME_APP_PACKAGE_NAME, SHOW_PERMS_SERVICE_CLASS))
+ .setAction(Intent.ACTION_UNINSTALL_PACKAGE);
+ showPermsIntent.putExtra(KEY_PACKAGE_NAME, packageName);
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Launching Intent " + showPermsIntent + " for " + packageName);
+ }
+ startService(showPermsIntent);
+ }
+
+ private Uri getIconFileUri(final String packageName, final Drawable d) {
+ if (d == null || !(d instanceof BitmapDrawable)) {
+ Log.e(TAG, "Drawable is not a BitmapDrawable for " + packageName);
+ return null;
+ }
+ File iconFile = WearPackageUtil.getIconFile(this, packageName);
+
+ if (iconFile == null) {
+ Log.e(TAG, "Could not get icon file for " + packageName);
+ return null;
+ }
+
+ FileOutputStream fos = null;
+ try {
+ // Convert bitmap to byte array
+ Bitmap bitmap = ((BitmapDrawable) d).getBitmap();
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
+
+ // Write the bytes into the file
+ fos = new FileOutputStream(iconFile);
+ fos.write(bos.toByteArray());
+ fos.flush();
+
+ return WearPackageIconProvider.getUriForPackage(packageName);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not convert drawable to icon file for package " + packageName, e);
+ return null;
+ } finally {
+ if (fos != null) {
+ try {
+ fos.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ private class PackageInstallObserver extends IPackageInstallObserver.Stub {
+ private Context mContext;
+ private PowerManager.WakeLock mWakeLock;
+ private int mStartId;
+ private String mApplicationPackageName;
+ private PackageInstallObserver(Context context, PowerManager.WakeLock wakeLock,
+ int startId, String applicationPackageName) {
+ mContext = context;
+ mWakeLock = wakeLock;
+ mStartId = startId;
+ mApplicationPackageName = applicationPackageName;
+ }
+
+ public void packageInstalled(String packageName, int returnCode) {
+ try {
+ // If installation failed, bail out and remove the ShowPermsStore entry
+ if (returnCode < 0) {
+ Log.e(TAG, "Package install failed " + mApplicationPackageName
+ + ", returnCode " + returnCode);
+ WearPackageUtil.removeFromPermStore(mContext, mApplicationPackageName);
+ return;
+ }
+
+ Log.i(TAG, "Package " + packageName + " was installed.");
+
+ // Delete tempFile from the file system.
+ File tempFile = WearPackageUtil.getTemporaryFile(mContext, packageName);
+ if (tempFile != null) {
+ tempFile.delete();
+ }
+
+ // Broadcast the "UPDATED" gmscore intent, normally sent by play store.
+ // TODO: Remove this broadcast if/when we get the play store to do this for us.
+ if (GMS_PACKAGE_NAME.equals(packageName)) {
+ Intent gmsInstalledIntent = new Intent(GMS_UPDATED_BROADCAST);
+ gmsInstalledIntent.setPackage(GMS_PACKAGE_NAME);
+ mContext.sendBroadcast(gmsInstalledIntent);
+ }
+ } finally {
+ finishService(mWakeLock, mStartId);
+ }
+ }
+ }
+
+ private class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
+ private PowerManager.WakeLock mWakeLock;
+ private int mStartId;
+
+ private PackageDeleteObserver(PowerManager.WakeLock wakeLock, int startId) {
+ mWakeLock = wakeLock;
+ mStartId = startId;
+ }
+
+ public void packageDeleted(String packageName, int returnCode) {
+ try {
+ if (returnCode >= 0) {
+ Log.i(TAG, "Package " + packageName + " was uninstalled.");
+ } else {
+ Log.e(TAG, "Package uninstall failed " + packageName + ", returnCode " +
+ returnCode);
+ }
+ } finally {
+ finishService(mWakeLock, mStartId);
+ }
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/wear/WearPackageUtil.java b/src/com/android/packageinstaller/wear/WearPackageUtil.java
new file mode 100644
index 00000000..688d6167
--- /dev/null
+++ b/src/com/android/packageinstaller/wear/WearPackageUtil.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.packageinstaller.wear;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageParser;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.text.TextUtils;
+import android.util.Log;
+
+import org.tukaani.xz.LZMAInputStream;
+import org.tukaani.xz.XZInputStream;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+
+public class WearPackageUtil {
+ private static final String TAG = "WearablePkgInstaller";
+
+ private static final String COMPRESSION_LZMA = "lzma";
+ private static final String COMPRESSION_XZ = "xz";
+
+ private static final String SHOW_PERMS_SERVICE_PKG_NAME = "com.google.android.wearable.app";
+ private static final String SHOW_PERMS_SERVICE_CLASS_NAME =
+ "com.google.android.clockwork.packagemanager.ShowPermsService";
+ private static final String EXTRA_PACKAGE_NAME
+ = "com.google.android.clockwork.EXTRA_PACKAGE_NAME";
+
+ public static File getTemporaryFile(Context context, String packageName) {
+ try {
+ File newFileDir = new File(context.getFilesDir(), "tmp");
+ newFileDir.mkdirs();
+ Os.chmod(newFileDir.getAbsolutePath(), 0771);
+ File newFile = new File(newFileDir, packageName + ".apk");
+ return newFile;
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Failed to open.", e);
+ return null;
+ }
+ }
+
+ public static File getIconFile(final Context context, final String packageName) {
+ try {
+ File newFileDir = new File(context.getFilesDir(), "images/icons");
+ newFileDir.mkdirs();
+ Os.chmod(newFileDir.getAbsolutePath(), 0771);
+ return new File(newFileDir, packageName + ".icon");
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Failed to open.", e);
+ return null;
+ }
+ }
+
+ /**
+ * In order to make sure that the Wearable Asset Manager has a reasonable apk that can be used
+ * by the PackageManager, we will parse it before sending it to the PackageManager.
+ * Unfortunately, PackageParser needs a file to parse. So, we have to temporarily convert the fd
+ * to a File.
+ *
+ * @param context
+ * @param fd FileDescriptor to convert to File
+ * @param packageName Name of package, will define the name of the file
+ * @param compressionAlg Can be null. For ALT mode the APK will be compressed. We will
+ * decompress it here
+ */
+ public static File getFileFromFd(Context context, ParcelFileDescriptor fd,
+ String packageName, @Nullable String compressionAlg) {
+ File newFile = getTemporaryFile(context, packageName);
+ if (fd == null || fd.getFileDescriptor() == null) {
+ return null;
+ }
+ InputStream fr = new ParcelFileDescriptor.AutoCloseInputStream(fd);
+ try {
+ if (TextUtils.equals(compressionAlg, COMPRESSION_XZ)) {
+ fr = new XZInputStream(fr);
+ } else if (TextUtils.equals(compressionAlg, COMPRESSION_LZMA)) {
+ fr = new LZMAInputStream(fr);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Compression was set to " + compressionAlg + ", but could not decode ", e);
+ return null;
+ }
+
+ int nRead;
+ byte[] data = new byte[1024];
+ try {
+ final FileOutputStream fo = new FileOutputStream(newFile);
+ while ((nRead = fr.read(data, 0, data.length)) != -1) {
+ fo.write(data, 0, nRead);
+ }
+ fo.flush();
+ fo.close();
+ Os.chmod(newFile.getAbsolutePath(), 0644);
+ return newFile;
+ } catch (IOException e) {
+ Log.e(TAG, "Reading from Asset FD or writing to temp file failed ", e);
+ return null;
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Could not set permissions on file ", e);
+ return null;
+ } finally {
+ try {
+ fr.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to close the file from FD ", e);
+ }
+ }
+ }
+
+ public static boolean hasLauncherActivity(PackageParser.Package pkg) {
+ if (pkg == null || pkg.activities == null) {
+ return false;
+ }
+
+ final int activityCount = pkg.activities.size();
+ for (int i = 0; i < activityCount; ++i) {
+ if (pkg.activities.get(i).intents != null) {
+ ArrayList<PackageParser.ActivityIntentInfo> intents =
+ pkg.activities.get(i).intents;
+ final int intentsCount = intents.size();
+ for (int j = 0; j < intentsCount; ++j) {
+ final PackageParser.ActivityIntentInfo intentInfo = intents.get(j);
+ if (intentInfo.hasAction(Intent.ACTION_MAIN)) {
+ if (intentInfo.hasCategory(Intent.CATEGORY_INFO) ||
+ intentInfo .hasCategory(Intent.CATEGORY_LAUNCHER)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public static void removeFromPermStore(Context context, String wearablePackageName) {
+ Intent newIntent = new Intent()
+ .setComponent(new ComponentName(
+ SHOW_PERMS_SERVICE_PKG_NAME, SHOW_PERMS_SERVICE_CLASS_NAME))
+ .setAction(Intent.ACTION_UNINSTALL_PACKAGE);
+ newIntent.putExtra(EXTRA_PACKAGE_NAME, wearablePackageName);
+ Log.i(TAG, "Sending removeFromPermStore to ShowPermsService " + newIntent
+ + " for " + wearablePackageName);
+ context.startService(newIntent);
+ }
+}