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/drawable/ic_dialog_alert_material.xml25
-rw-r--r--res/drawable/ic_info.xml3
-rw-r--r--res/drawable/ic_more_items.xml29
-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/layout/app_details.xml8
-rw-r--r--res/layout/grant_permissions.xml48
-rw-r--r--res/layout/header.xml15
-rw-r--r--res/layout/install_confirm.xml3
-rw-r--r--res/layout/permission_description.xml6
-rw-r--r--res/layout/permissions_frame.xml4
-rw-r--r--res/layout/preference_permissions.xml2
-rw-r--r--res/layout/preference_permissions_switch.xml2
-rw-r--r--res/layout/uninstall_confirm.xml3
-rw-r--r--res/values-af-watch/strings.xml25
-rw-r--r--res/values-af/strings.xml4
-rw-r--r--res/values-am-watch/strings.xml25
-rw-r--r--res/values-am/strings.xml4
-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-television/strings.xml2
-rw-r--r--res/values-da-watch/strings.xml25
-rw-r--r--res/values-da/strings.xml4
-rw-r--r--res/values-de-television/strings.xml2
-rw-r--r--res/values-de-watch/strings.xml25
-rw-r--r--res/values-de/strings.xml48
-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.xml4
-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.xml4
-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.xml4
-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.xml8
-rw-r--r--res/values-nl-watch/strings.xml25
-rw-r--r--res/values-nl/strings.xml8
-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.xml4
-rw-r--r--res/values-pt-rBR-watch/strings.xml25
-rw-r--r--res/values-pt-rBR/strings.xml4
-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.xml4
-rw-r--r--res/values-ro-watch/strings.xml25
-rw-r--r--res/values-ro/strings.xml4
-rw-r--r--res/values-round/dimens.xml26
-rw-r--r--res/values-ru-watch/strings.xml25
-rw-r--r--res/values-ru/strings.xml4
-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.xml8
-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.xml4
-rw-r--r--res/values-te-rIN-watch/strings.xml25
-rw-r--r--res/values-te-rIN/strings.xml2
-rw-r--r--res/values-television/colors.xml7
-rw-r--r--res/values-television/styles.xml37
-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.xml (renamed from res/drawable/header_background.xml)11
-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.xml4
-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
-rwxr-xr-xres/values/colors.xml31
-rw-r--r--res/values/strings.xml5
-rwxr-xr-xres/values/styles.xml31
-rw-r--r--res/values/themes.xml10
-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/PermissionApps.java3
-rw-r--r--src/com/android/packageinstaller/permission/model/PermissionGroups.java5
-rw-r--r--src/com/android/packageinstaller/permission/model/PermissionStatusReceiver.java107
-rw-r--r--src/com/android/packageinstaller/permission/ui/ButtonBarLayout.java117
-rw-r--r--src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java17
-rw-r--r--src/com/android/packageinstaller/permission/ui/GrantPermissionsViewHandler.java2
-rw-r--r--src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java176
-rw-r--r--src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java29
-rw-r--r--src/com/android/packageinstaller/permission/ui/OverlayWarningDialog.java1
-rw-r--r--src/com/android/packageinstaller/permission/ui/PreferenceImageView.java69
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/AllAppPermissionsFragment.java214
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/AppPermissionsFragment.java404
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.java (renamed from src/com/android/packageinstaller/permission/ui/GrantPermissionsDefaultViewHandler.java)16
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/ManagePermissionsFragment.java268
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java428
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/PermissionsFrameFragment.java121
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/SettingsWithHeader.java (renamed from src/com/android/packageinstaller/permission/ui/SettingsWithHeader.java)6
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/AllAppPermissionsFragment.java (renamed from src/com/android/packageinstaller/permission/ui/AllAppPermissionsFragment.java)2
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/AppPermissionsFragment.java (renamed from src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java)3
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/GrantPermissionsViewHandlerImpl.java (renamed from src/com/android/packageinstaller/permission/ui/GrantPermissionsTvViewHandler.java)9
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/ManagePermissionsFragment.java (renamed from src/com/android/packageinstaller/permission/ui/ManagePermissionsFragment.java)4
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java (renamed from src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java)6
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/PermissionsFrameFragment.java (renamed from src/com/android/packageinstaller/permission/ui/PermissionsFrameFragment.java)21
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/SettingsWithHeader.java86
-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/LocationUtils.java17
-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
339 files changed, 10154 insertions, 237 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/drawable/ic_dialog_alert_material.xml b/res/drawable/ic_dialog_alert_material.xml
new file mode 100644
index 00000000..8bd2e0ba
--- /dev/null
+++ b/res/drawable/ic_dialog_alert_material.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:pathData="M1,21l22,0L12,2L1,21zM13,18l-2,0l0,-2l2,0L13,18zM13,14l-2,0l0,-4l2,0L13,14z"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/res/drawable/ic_info.xml b/res/drawable/ic_info.xml
index f80a41cb..029ff1b5 100644
--- a/res/drawable/ic_info.xml
+++ b/res/drawable/ic_info.xml
@@ -17,7 +17,8 @@ Copyright (C) 2015 The Android Open Source Project
android:width="24.0dp"
android:height="24.0dp"
android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:viewportHeight="24.0"
+ android:tint="?attr/colorControlNormal">
<path
android:pathData="M0 0h24v24H0z"
android:fillColor="#00000000"/>
diff --git a/res/drawable/ic_more_items.xml b/res/drawable/ic_more_items.xml
new file mode 100644
index 00000000..5fdcdcef
--- /dev/null
+++ b/res/drawable/ic_more_items.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7
+7v2h14V7H7z" />
+ <path
+ android:pathData="M0 0h24v24H0z" />
+</vector> \ No newline at end of file
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/layout/app_details.xml b/res/layout/app_details.xml
index 6a330c74..8f7d2cff 100644
--- a/res/layout/app_details.xml
+++ b/res/layout/app_details.xml
@@ -4,9 +4,9 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
-
+
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -32,7 +32,7 @@ installation screens
android:layout_width="32dip"
android:layout_height="32dip"
android:layout_marginStart="8dip"
- android:background="@color/transparent"
+ android:background="@android:color/transparent"
android:layout_alignParentStart="true"
android:gravity="start"
android:scaleType="centerCrop"/>
@@ -61,6 +61,6 @@ installation screens
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</FrameLayout>
-
+
</RelativeLayout>
diff --git a/res/layout/grant_permissions.xml b/res/layout/grant_permissions.xml
index b3565240..463f0ccd 100644
--- a/res/layout/grant_permissions.xml
+++ b/res/layout/grant_permissions.xml
@@ -18,6 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
+
<LinearLayout
android:id="@+id/dialog_container"
android:layout_width="fill_parent"
@@ -46,10 +47,10 @@
android:visibility="gone">
</CheckBox>
- <com.android.internal.widget.ButtonBarLayout
+ <com.android.packageinstaller.permission.ui.ButtonBarLayout
android:id="@+id/button_group"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingStart="2dip"
android:paddingTop="16dip">
@@ -58,12 +59,13 @@
android:id="@+id/current_page_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="start|bottom"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:paddingEnd="12dp"
android:singleLine="true"
- style="@android:style/TextAppearance.Material.Body2"
- android:textColor="@color/grant_permissions_progress_color"
+ style="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
android:visibility="invisible">
</TextView>
@@ -72,24 +74,36 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
- android:visibility="invisible" />
+ android:visibility="invisible" >
+ </Space>
- <Button
- android:id="@+id/permission_deny_button"
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="?android:attr/buttonBarButtonStyle"
- android:text="@string/grant_dialog_button_deny" />
+ android:layout_gravity="end"
+ android:orientation="horizontal" >
- <Button
- android:id="@+id/permission_allow_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="?android:attr/buttonBarButtonStyle"
- android:layout_marginStart="8dip"
- android:text="@string/grant_dialog_button_allow" />
+ <Button
+ android:id="@+id/permission_deny_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="?android:attr/buttonBarButtonStyle"
+ android:text="@string/grant_dialog_button_deny" >
+ </Button>
- </com.android.internal.widget.ButtonBarLayout>
+ <Button
+ android:id="@+id/permission_allow_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="?android:attr/buttonBarButtonStyle"
+ android:layout_marginStart="8dip"
+ android:text="@string/grant_dialog_button_allow" >
+ </Button>
+
+ </LinearLayout>
+
+ </com.android.packageinstaller.permission.ui.ButtonBarLayout>
</LinearLayout>
+
</com.android.packageinstaller.permission.ui.ManualLayoutFrame>
diff --git a/res/layout/header.xml b/res/layout/header.xml
index 0e000a4d..f158e442 100644
--- a/res/layout/header.xml
+++ b/res/layout/header.xml
@@ -17,9 +17,8 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
- android:background="@drawable/header_background"
- android:gravity="center_vertical"
- android:theme="@style/Theme.Header.Settings" >
+ android:background="?android:attr/colorPrimary"
+ android:gravity="center_vertical" >
<ImageView android:id="@+id/icon"
android:layout_width="@dimen/header_subsettings_margin_start"
@@ -31,12 +30,11 @@
android:id="@+id/name"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:layout_toStartOf="@+id/app_settings"
android:layout_marginStart="@dimen/header_subsettings_margin_start"
android:layout_alignWithParentIfMissing="true"
android:layout_centerVertical="true"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="@android:color/white"
+ android:textColor="?android:attr/textColorPrimaryInverse"
android:textAlignment="viewStart" />
<ImageView
@@ -52,11 +50,4 @@
android:src="@drawable/ic_info"
style="?android:attr/borderlessButtonStyle" />
- <View
- android:id="@+id/row_divider"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/listDivider" />
-
</RelativeLayout>
-
diff --git a/res/layout/install_confirm.xml b/res/layout/install_confirm.xml
index 26f3bedd..8144b2b0 100644
--- a/res/layout/install_confirm.xml
+++ b/res/layout/install_confirm.xml
@@ -31,9 +31,10 @@
android:id="@+id/install_confirm_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
android:text="@string/install_confirm_question"
android:textAppearance="?android:attr/textAppearanceMedium"
- style="@style/padded"
android:paddingTop="4dip" />
<ImageView
diff --git a/res/layout/permission_description.xml b/res/layout/permission_description.xml
index 3f1cf434..2a00e9bf 100644
--- a/res/layout/permission_description.xml
+++ b/res/layout/permission_description.xml
@@ -26,15 +26,15 @@
android:layout_height="36dip"
android:layout_marginTop="3dp"
android:tint="?android:attr/colorAccent"
- android:scaleType="fitCenter" />
+ android:scaleType="fitCenter" >
+ </ImageView>
<TextView
android:id="@+id/permission_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/permission_icon"
- android:lineSpacingMultiplier="1.024"
- android:fontFamily="@*android:string/font_family_body_2_material"
+ android:layout_marginTop="3dp"
android:paddingStart="16dip"
android:paddingEnd="8dip"
style="?android:attr/textAppearanceMedium">
diff --git a/res/layout/permissions_frame.xml b/res/layout/permissions_frame.xml
index 8f1f2789..156af57e 100644
--- a/res/layout/permissions_frame.xml
+++ b/res/layout/permissions_frame.xml
@@ -30,8 +30,8 @@
android:layout_height="match_parent"
android:text="@string/no_permissions"
android:gravity="center"
- android:textAppearance="@android:style/TextAppearance.Large"
- />
+ style="?android:attr/textAppearanceLarge">
+ </TextView>
</FrameLayout>
diff --git a/res/layout/preference_permissions.xml b/res/layout/preference_permissions.xml
index 67b4469c..631d56bd 100644
--- a/res/layout/preference_permissions.xml
+++ b/res/layout/preference_permissions.xml
@@ -37,7 +37,7 @@
android:paddingEnd="20dp"
android:paddingTop="4dp"
android:paddingBottom="4dp">
- <com.android.internal.widget.PreferenceImageView
+ <com.android.packageinstaller.permission.ui.PreferenceImageView
android:id="@android:id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
diff --git a/res/layout/preference_permissions_switch.xml b/res/layout/preference_permissions_switch.xml
index cf444d96..78d2a4ef 100644
--- a/res/layout/preference_permissions_switch.xml
+++ b/res/layout/preference_permissions_switch.xml
@@ -37,7 +37,7 @@
android:paddingEnd="20dp"
android:paddingTop="4dp"
android:paddingBottom="4dp">
- <com.android.internal.widget.PreferenceImageView
+ <com.android.packageinstaller.permission.ui.PreferenceImageView
android:id="@android:id/icon"
android:layout_width="36dp"
android:layout_height="36dp"
diff --git a/res/layout/uninstall_confirm.xml b/res/layout/uninstall_confirm.xml
index f604023f..78270f60 100644
--- a/res/layout/uninstall_confirm.xml
+++ b/res/layout/uninstall_confirm.xml
@@ -40,9 +40,10 @@
android:id="@+id/activity_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
android:textColor="?android:attr/textColorSecondary"
android:textAppearance="?android:attr/textAppearanceMedium"
- style="@style/padded"
android:visibility="gone" />
<!-- The snippet (title & icon) about the application being uninstalled. -->
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 d814aa9c..635c28b3 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -90,7 +90,7 @@
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Laat toe"</string>
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Weier"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> van <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="5209102765005869454">"Laat <xliff:g id="APP_NAME">%1$s</xliff:g> toe om te <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="5209102765005869454">"Laat <xliff:g id="APP_NAME">%1$s</xliff:g> toe om <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Programme"</string>
<string name="app_permissions" msgid="3146758905824597178">"Programtoestemmings"</string>
<string name="never_ask_again" msgid="3798895821072102967">"Moet nooit weer vra nie"</string>
@@ -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 de1f8538..0b0396fa 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -90,7 +90,7 @@
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"ፍቀድ"</string>
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"ከልክል"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> ከ<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="5209102765005869454">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="ACTION">%2$s</xliff:g> እንዲያደርግ ይፈቀድለት?"</string>
+ <string name="permission_warning_template" msgid="5209102765005869454">"<xliff:g id="APP_NAME">%1$s</xliff:g> መተግበሪያ <xliff:g id="ACTION">%2$s</xliff:g> እንዲያደርግ ይፈቀድለት?"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"መተግበሪያዎች"</string>
<string name="app_permissions" msgid="3146758905824597178">"የመተግበሪያ ፈቃዶች"</string>
<string name="never_ask_again" msgid="3798895821072102967">"ሁለተኛ እንዳትጠይቅ"</string>
@@ -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-television/strings.xml b/res/values-da-television/strings.xml
index 63b9de88..5e28b62f 100644
--- a/res/values-da-television/strings.xml
+++ b/res/values-da-television/strings.xml
@@ -17,7 +17,7 @@
<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="5694574989758145558">"Afvis, og spørg ikke igen"</string>
- <string name="grant_dialog_how_to_change" msgid="615414835189256888">"Du kan ændre dette på et senere tidspunkt i Indstillinger og apps"</string>
+ <string name="grant_dialog_how_to_change" msgid="615414835189256888">"Du kan altid ændre dette i Indstillinger &gt; Apps"</string>
<string name="current_permission_template" msgid="4793247012451594523">"<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="7330308025768596149">"Vis systemapps"</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 90f0e8a0..b88dc3b6 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -105,7 +105,7 @@
<string name="app_permissions_group_summary" msgid="4787239772223699263">"<xliff:g id="COUNT_0">%1$d</xliff:g> ud af <xliff:g id="COUNT_1">%2$d</xliff:g> apps har tilladelse"</string>
<string name="menu_show_system" msgid="6773743421743728921">"Vis systemapps"</string>
<string name="menu_hide_system" msgid="7595471742649432977">"Skjul systemapps"</string>
- <string name="permission_title" msgid="6495415273398916381">"<xliff:g id="PERMISSION">%1$s</xliff:g> tilladelser"</string>
+ <string name="permission_title" msgid="6495415273398916381">"<xliff:g id="PERMISSION">%1$s</xliff:g>-tilladelser"</string>
<string name="no_apps" msgid="1965493419005012569">"Ingen apps"</string>
<string name="location_settings" msgid="1774875730854491297">"Placeringsindstillinger"</string>
<string name="location_warning" msgid="8778701356292735971">"<xliff:g id="APP_NAME">%1$s</xliff:g> udbyder placeringstjenester for denne enhed. Adgangen til din placering kan ændres i Placeringsindstillinger."</string>
@@ -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-television/strings.xml b/res/values-de-television/strings.xml
index cf52f8ca..2eae5499 100644
--- a/res/values-de-television/strings.xml
+++ b/res/values-de-television/strings.xml
@@ -17,7 +17,7 @@
<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="5694574989758145558">"Ablehnen und nicht mehr fragen"</string>
- <string name="grant_dialog_how_to_change" msgid="615414835189256888">"Sie können dies später unter \"Einstellungen &gt; Apps\" ändern."</string>
+ <string name="grant_dialog_how_to_change" msgid="615414835189256888">"Du kannst dies später unter \"Einstellungen &gt; Apps\" ändern."</string>
<string name="current_permission_template" msgid="4793247012451594523">"<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="7330308025768596149">"System-Apps anzeigen"</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 76776b60..0208d4a2 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -25,12 +25,12 @@
<string name="unknown" msgid="4742479012767208045">"Unbekannt"</string>
<string name="installing" msgid="8613631001631998372">"Wird installiert..."</string>
<string name="install_done" msgid="3682715442154357097">"App wurde installiert."</string>
- <string name="install_confirm_question" msgid="7295206719219043890">"Möchten Sie diese App installieren? Sie erhält dann folgende Berechtigungen:"</string>
- <string name="install_confirm_question_no_perms" msgid="5918305641302873520">"Möchten Sie diese App installieren? Sie benötigt keinen besonderen Zugriff."</string>
- <string name="install_confirm_question_update" msgid="4624159567361487964">"Möchten Sie ein Update für diese vorhandene App installieren? Ihre vorhandenen Daten bleiben erhalten. Die aktualisierte App erhält Zugriff auf:"</string>
- <string name="install_confirm_question_update_system" msgid="1302330093676416336">"Möchten Sie ein Update für diese integrierte App installieren? Ihre vorhandenen Daten bleiben erhalten. Die aktualisierte App erhält Zugriff auf:"</string>
- <string name="install_confirm_question_update_no_perms" msgid="4885928136844618944">"Möchten Sie ein Update für diese bestehende App installieren? Ihre vorhandenen Daten bleiben erhalten. Sie benötigen keine besonderen Zugriffsrechte."</string>
- <string name="install_confirm_question_update_system_no_perms" msgid="7676593512694724374">"Möchten Sie ein Update für diese integrierte App installieren? Ihre vorhandenen Daten bleiben erhalten. Sie benötigen keine besonderen Zugriffsrechte."</string>
+ <string name="install_confirm_question" msgid="7295206719219043890">"Möchtest du diese App installieren? Sie erhält dann folgende Berechtigungen:"</string>
+ <string name="install_confirm_question_no_perms" msgid="5918305641302873520">"Möchtest du diese App installieren? Sie benötigt keinen besonderen Zugriff."</string>
+ <string name="install_confirm_question_update" msgid="4624159567361487964">"Möchtest du ein Update für diese vorhandene App installieren? Deine vorhandenen Daten bleiben erhalten. Die aktualisierte App erhält Zugriff auf:"</string>
+ <string name="install_confirm_question_update_system" msgid="1302330093676416336">"Möchtest du ein Update für diese integrierte App installieren? Deine vorhandenen Daten bleiben erhalten. Die aktualisierte App erhält Zugriff auf:"</string>
+ <string name="install_confirm_question_update_no_perms" msgid="4885928136844618944">"Möchtest du ein Update für diese bestehende App installieren? Deine vorhandenen Daten bleiben erhalten. Die App benötigt keine besonderen Zugriffsrechte."</string>
+ <string name="install_confirm_question_update_system_no_perms" msgid="7676593512694724374">"Möchtest du ein Update für diese integrierte App installieren? Deine vorhandenen Daten bleiben erhalten. Die App benötigt keine besonderen Zugriffsrechte."</string>
<string name="install_failed" msgid="6579998651498970899">"App wurde nicht installiert."</string>
<string name="install_failed_invalid_apk" msgid="1287935707565682604">"Das Paket ist offenbar beschädigt."</string>
<string name="install_failed_inconsistent_certificates" msgid="1517751954440692054">"Ein Paket mit dem gleichen Namen, aber in Konflikt stehender Signatur, ist bereits installiert."</string>
@@ -40,36 +40,36 @@
<string name="install_failed_cpu_abi_incompatible" product="default" msgid="4433316303249711331">"Diese App ist mit Ihrem Telefon nicht kompatibel."</string>
<string name="install_failed_file_not_found" msgid="1958430133396322619">"Das angegebene Paket wurde gelöscht, bevor die Installation abgeschlossen werden konnte."</string>
<string name="install_failed_verify_failed" msgid="5567372439890440205">"Das Paket hat die Prüfung nicht bestanden und kann daher nicht installiert werden."</string>
- <string name="install_failed_verify_timeout" msgid="7083090219270140373">"Bei der Paketüberprüfung ist eine Zeitüberschreitung aufgetreten. Wiederholen Sie die Installation."</string>
+ <string name="install_failed_verify_timeout" msgid="7083090219270140373">"Bei der Paketüberprüfung ist eine Zeitüberschreitung aufgetreten. Wiederhole die Installation."</string>
<string name="install_failed_msg" product="tablet" msgid="8368835262605608787">"<xliff:g id="APP_NAME">%1$s</xliff:g> konnte nicht auf Ihrem Tablet installiert werden."</string>
<string name="install_failed_msg" product="tv" msgid="3990457938384021566">"<xliff:g id="APP_NAME">%1$s</xliff:g> konnte nicht auf Ihrem Fernseher installiert werden."</string>
<string name="install_failed_msg" product="default" msgid="8554909560982962052">"<xliff:g id="APP_NAME">%1$s</xliff:g> konnte nicht auf Ihrem Telefon installiert werden."</string>
<string name="launch" msgid="4826921505917605463">"Öffnen"</string>
<string name="unknown_apps_dlg_title" msgid="2855558586206583032">"Installation gesperrt"</string>
- <string name="unknown_apps_dlg_text" product="tablet" msgid="7504186369474734767">"Aus Sicherheitsgründen können Sie auf Ihrem Tablet keine Apps von unbekannten Quellen installieren."</string>
- <string name="unknown_apps_dlg_text" product="tv" msgid="7195713985140602351">"Aus Sicherheitsgründen können Sie auf dem Fernseher keine Apps von unbekannten Quellen installieren."</string>
- <string name="unknown_apps_dlg_text" product="default" msgid="133213135679009316">"Aus Sicherheitsgründen können Sie auf Ihrem Telefon keine Apps von unbekannten Quellen installieren."</string>
+ <string name="unknown_apps_dlg_text" product="tablet" msgid="7504186369474734767">"Aus Sicherheitsgründen kannst du auf deinem Tablet keine Apps von unbekannten Quellen installieren."</string>
+ <string name="unknown_apps_dlg_text" product="tv" msgid="7195713985140602351">"Aus Sicherheitsgründen kannst du auf dem Fernseher keine Apps von unbekannten Quellen installieren."</string>
+ <string name="unknown_apps_dlg_text" product="default" msgid="133213135679009316">"Aus Sicherheitsgründen kannst du auf deinem Telefon keine Apps von unbekannten Quellen installieren."</string>
<string name="unknown_apps_admin_dlg_text" msgid="1189146324736698462">"Ihr Administrator erlaubt die Installation von Apps aus unbekannten Quellen nicht."</string>
<string name="ok" msgid="3468756155452870475">"OK"</string>
<string name="settings" msgid="6743583734099755409">"Einstellungen"</string>
<string name="allow_source_dlg_title" msgid="7568985073502399415">"Neue Quelle für Apps"</string>
- <string name="allow_source_dlg_text" msgid="3927580956764099076">"<xliff:g id="APP_NAME">%1$s</xliff:g> möchte andere Apps installieren.\n\nMöchten Sie dies jetzt und in Zukunft zulassen?"</string>
+ <string name="allow_source_dlg_text" msgid="3927580956764099076">"<xliff:g id="APP_NAME">%1$s</xliff:g> möchte andere Apps installieren.\n\nMöchtest du dies jetzt und in Zukunft zulassen?"</string>
<string name="manage_applications" msgid="4033876279091996596">"Apps verwalten"</string>
<string name="dlg_app_replacement_title" msgid="1232230739563820951">"App ersetzen?"</string>
- <string name="dlg_app_replacement_statement" msgid="2992911899989907492">"Die App, die Sie momentan installieren, wird eine andere App ersetzen.\n\nAlle Ihre bisherigen Nutzerdaten werden gespeichert."</string>
+ <string name="dlg_app_replacement_statement" msgid="2992911899989907492">"Die App, die du momentan installierst, wird eine andere App ersetzen.\n\nAlle deine bisherigen Nutzerdaten werden gespeichert."</string>
<string name="dlg_sys_app_replacement_statement" msgid="1900046590819605929">"Dies ist eine Systemanwendung.\n\nAlle Ihre bisherigen Nutzerdaten werden gespeichert."</string>
<string name="out_of_space_dlg_title" msgid="7843674437613797326">"Kein freier Speicher vorhanden"</string>
- <string name="out_of_space_dlg_text" msgid="4774775404294282216">"<xliff:g id="APP_NAME">%1$s</xliff:g> konnte nicht installiert werden. Geben Sie Speicherplatz frei und versuchen Sie es erneut."</string>
+ <string name="out_of_space_dlg_text" msgid="4774775404294282216">"<xliff:g id="APP_NAME">%1$s</xliff:g> konnte nicht installiert werden. Gib Speicherplatz frei und versuche es erneut."</string>
<string name="dlg_ok" msgid="6944357727705699232">"OK"</string>
<string name="app_not_found_dlg_title" msgid="2692335460569505484">"App nicht gefunden"</string>
<string name="app_not_found_dlg_text" msgid="6107465056055095930">"Die App wurde nicht in der Liste der installierten Apps gefunden."</string>
<string name="uninstall_application_title" msgid="1860074100811653963">"App deinstallieren"</string>
<string name="uninstall_update_title" msgid="4146940097553335390">"Update deinstallieren"</string>
<string name="uninstall_activity_text" msgid="6680688689803932550">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> gehört zu folgender App:"</string>
- <string name="uninstall_application_text" msgid="6691975835951187030">"Möchten Sie diese App deinstallieren?"</string>
- <string name="uninstall_application_text_all_users" msgid="5574704453233525222">"Möchten Sie diese App für "<b>"alle"</b>" Nutzer entfernen? Die App und alle zugehörigen Daten werden für "<b>"alle"</b>" Nutzer des Geräts entfernt."</string>
- <string name="uninstall_application_text_user" msgid="8766882355635485733">"Möchten Sie diese App für den Nutzer <xliff:g id="USERNAME">%1$s</xliff:g> deinstallieren?"</string>
- <string name="uninstall_update_text" msgid="2056387942084605027">"Möchten Sie diese App durch die Werksversion ersetzen?"</string>
+ <string name="uninstall_application_text" msgid="6691975835951187030">"Möchtest du diese App deinstallieren?"</string>
+ <string name="uninstall_application_text_all_users" msgid="5574704453233525222">"Möchtest du diese App für "<b>"alle"</b>" Nutzer entfernen? Die App und alle zugehörigen Daten werden für "<b>"alle"</b>" Nutzer des Geräts entfernt."</string>
+ <string name="uninstall_application_text_user" msgid="8766882355635485733">"Möchtest du diese App für den Nutzer <xliff:g id="USERNAME">%1$s</xliff:g> deinstallieren?"</string>
+ <string name="uninstall_update_text" msgid="2056387942084605027">"Möchtest du diese App durch die Werksversion ersetzen?"</string>
<string name="uninstalling" msgid="5556217435895938250">"Wird deinstalliert..."</string>
<string name="uninstall_done" msgid="3792487853420281888">"Deinstallation abgeschlossen"</string>
<string name="uninstall_failed" msgid="631122574306299512">"Deinstallation fehlgeschlagen"</string>
@@ -86,9 +86,9 @@
<string name="privacyPerms" msgid="1850527049572617">"Datenschutz"</string>
<string name="devicePerms" msgid="6733560207731294504">"Gerätezugriff"</string>
<string name="no_new_perms" msgid="6657813692169565975">"Für dieses Update sind keine neuen Berechtigungen erforderlich."</string>
- <string name="grant_confirm_question" msgid="4690289297029223742">"Möchten Sie die folgenden Berechtigungen gewähren? Diese ermöglichen den Zugriff auf Folgendes:"</string>
+ <string name="grant_confirm_question" msgid="4690289297029223742">"Möchtest du die folgenden Berechtigungen gewähren? Sie ermöglichen den Zugriff auf Folgendes:"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Zulassen"</string>
- <string name="grant_dialog_button_deny" msgid="2176510645406614340">"Verweigern"</string>
+ <string name="grant_dialog_button_deny" msgid="2176510645406614340">"Ablehnen"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> von <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
<string name="permission_warning_template" msgid="5209102765005869454">"<xliff:g id="APP_NAME">%1$s</xliff:g> ermöglichen, <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Apps"</string>
@@ -100,7 +100,7 @@
<item quantity="other">Noch <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="one">Noch <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
- <string name="old_sdk_deny_warning" msgid="3872277112584842615">"Diese App wurde für eine ältere Version von Android konzipiert. Wenn Sie keine Berechtigung erteilen, funktioniert die App möglicherweise nicht mehr ordnungsgemäß."</string>
+ <string name="old_sdk_deny_warning" msgid="3872277112584842615">"Diese App wurde für eine ältere Version von Android konzipiert. Wenn du keine Berechtigung erteilst, funktioniert die App möglicherweise nicht mehr ordnungsgemäß."</string>
<string name="default_permission_description" msgid="4992892207044156668">"Unbekannte Aktion durchführen"</string>
<string name="app_permissions_group_summary" msgid="4787239772223699263">"<xliff:g id="COUNT_0">%1$d</xliff:g> von <xliff:g id="COUNT_1">%2$d</xliff:g> Apps sind berechtigt."</string>
<string name="menu_show_system" msgid="6773743421743728921">"System anzeigen"</string>
@@ -108,14 +108,16 @@
<string name="permission_title" msgid="6495415273398916381">"Berechtigungen für <xliff:g id="PERMISSION">%1$s</xliff:g>"</string>
<string name="no_apps" msgid="1965493419005012569">"Keine Apps"</string>
<string name="location_settings" msgid="1774875730854491297">"Standorteinstellungen"</string>
- <string name="location_warning" msgid="8778701356292735971">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist ein Anbieter von Standortdiensten für dieses Gerät. Die Berechtigungen für den Zugriff auf Ihren Standort können Sie in den Standorteinstellungen ändern."</string>
- <string name="system_warning" msgid="7103819124542305179">"Wenn Sie diese Berechtigung deaktivieren, funktionieren grundlegende Funktionen Ihres Geräts möglicherweise nicht mehr ordnungsgemäß."</string>
+ <string name="location_warning" msgid="8778701356292735971">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist ein Anbieter von Standortdiensten für dieses Gerät. Die Berechtigungen für den Zugriff auf deinen Standort kannst du in den Standorteinstellungen ändern."</string>
+ <string name="system_warning" msgid="7103819124542305179">"Wenn du diese Berechtigung deaktivierst, funktionieren grundlegende Funktionen deines Geräts möglicherweise nicht mehr ordnungsgemäß."</string>
<string name="permission_summary_enforced_by_policy" msgid="3418617316188986205">"Von Richtlinien durchgesetzt"</string>
<string name="loading" msgid="7811651799620593731">"Wird geladen…"</string>
<string name="all_permissions" msgid="5156669007784613042">"Alle Berechtigungen"</string>
<string name="other_permissions" msgid="2016192512386091933">"Andere App-Funktionen"</string>
<string name="permission_request_title" msgid="1204446718549121199">"Berechtigungsanfrage"</string>
<string name="screen_overlay_title" msgid="3021729846864038529">"Display-Overlay erkannt"</string>
- <string name="screen_overlay_message" msgid="2141944461571677331">"Um diese Berechtigungseinstellung zu ändern, müssen Sie zunächst das Display-Overlay über \"Einstellungen\" &gt; \"Apps\" deaktivieren."</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 25d900c6..27c509bb 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="2738748390251381682">"Programme d\'installation de la trousse"</string>
+ <string name="app_name" msgid="2738748390251381682">"Programme installation trousse"</string>
<string name="next" msgid="3057143178373252333">"Suivante"</string>
<string name="install" msgid="5896438203900042068">"Installer"</string>
<string name="done" msgid="3889387558374211719">"Terminé"</string>
@@ -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 55867cc9..d4bd8cf9 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -100,7 +100,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>개 더보기</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>개 더보기</item>
</plurals>
- <string name="old_sdk_deny_warning" msgid="3872277112584842615">"이 앱은 Android 이전 버전에 맞게 설계되었습니다. 권한이 거부되면 정상적으로 작동하지 않을 수 있습니다."</string>
+ <string name="old_sdk_deny_warning" msgid="3872277112584842615">"이 앱은 Android 이전 버전에 맞게 설계되었습니다. 권한을 거부하면 정상적으로 작동하지 않을 수 있습니다."</string>
<string name="default_permission_description" msgid="4992892207044156668">"알 수 없는 작업 수행"</string>
<string name="app_permissions_group_summary" msgid="4787239772223699263">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="COUNT_1">%2$d</xliff:g>개 앱 허용됨"</string>
<string name="menu_show_system" msgid="6773743421743728921">"시스템 표시"</string>
@@ -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 8cc487b2..c7cac3f8 100644
--- a/res/values-mk-rMK/strings.xml
+++ b/res/values-mk-rMK/strings.xml
@@ -51,7 +51,7 @@
<string name="unknown_apps_dlg_text" product="default" msgid="133213135679009316">"За безбедност, вашиот телефон е подесен да блокира инсталирање апликации добиени од непознати извори."</string>
<string name="unknown_apps_admin_dlg_text" msgid="1189146324736698462">"Вашиот администратор не дозволува инсталација на апликации добиени од непознати извори."</string>
<string name="ok" msgid="3468756155452870475">"Во ред"</string>
- <string name="settings" msgid="6743583734099755409">"Подесувања"</string>
+ <string name="settings" msgid="6743583734099755409">"Поставки"</string>
<string name="allow_source_dlg_title" msgid="7568985073502399415">"Нов извор за апликации"</string>
<string name="allow_source_dlg_text" msgid="3927580956764099076">"<xliff:g id="APP_NAME">%1$s</xliff:g> сака да инсталира други апликации.\n\nДозволи го ова сега и во иднина?"</string>
<string name="manage_applications" msgid="4033876279091996596">"Управувај со апликации"</string>
@@ -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 4a3c6708..8e0c4243 100644
--- a/res/values-ne-rNP/strings.xml
+++ b/res/values-ne-rNP/strings.xml
@@ -28,7 +28,7 @@
<string name="install_confirm_question" msgid="7295206719219043890">"के तपाईँ यो अनुप्रयोग स्थापन गर्न चाहनु हुन्छ? यसले पहुँच प्राप्त गर्ने छ:"</string>
<string name="install_confirm_question_no_perms" msgid="5918305641302873520">"के तपाईँ यस अनुप्रयोगलाई जडान गर्न चाहनु हुन्छ? यसको लागि कुनै विशेष पहुँचको आवश्यकता पर्दैन।"</string>
<string name="install_confirm_question_update" msgid="4624159567361487964">"के तपाईँसँग अहिले भईरहेको अनुप्रयोगको एक अपडेट लाई स्थापित गर्न चाहानुहुन्छ? तपाईँको अहिलेको डेटा हराउने छैन। अपडेट भएको अनुप्रयोग पहुँच पाउनेछ मा:"</string>
- <string name="install_confirm_question_update_system" msgid="1302330093676416336">"के तपाईं यस पूर्व-निर्मित अनुप्रयोगमा अपडेट स्थापित गर्न चाहनु हुन्छ? तपाईंको रहेको डेटा हराउने छैन। अपडेट गरिएको अनुप्रयोगले पहुँच पाउने छ:"</string>
+ <string name="install_confirm_question_update_system" msgid="1302330093676416336">"के तपाईँ यस पूर्व-निर्मित अनुप्रयोगमा अपडेट स्थापित गर्न चाहनु हुन्छ? तपाईँको रहेको डेटा हराउने छैन। अपडेट गरिएको अनुप्रयोगले पहुँच पाउने छ:"</string>
<string name="install_confirm_question_update_no_perms" msgid="4885928136844618944">"के तपाईँसँग अहिले भइरहेको अनुप्रयोगको एउटा अपडेटलाई स्थापित गर्न चाहनु हुन्छ? तपाईँको अहिलेको डेटा हराउने छैन। यसलाई कुनै विशेष पहुँचको आवश्यकता छैन।"</string>
<string name="install_confirm_question_update_system_no_perms" msgid="7676593512694724374">"के तपाईँ यस जोडिएको अनुप्रयोगको एउटा अपडेटलाई स्थापित गर्न चाहनुहुन्छ? तपाईँको अहिलेको डेटा हराउने छैन। यसलाई कुनै विशेष पहुँचको आवश्यकता छैन।"</string>
<string name="install_failed" msgid="6579998651498970899">"अनुप्रयोग स्थापना भएन।"</string>
@@ -67,7 +67,7 @@
<string name="uninstall_update_title" msgid="4146940097553335390">"परिस्कारहरू अस्थापना गर्नुहोस्"</string>
<string name="uninstall_activity_text" msgid="6680688689803932550">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> निम्न अनुप्रयोगको अंश हो:"</string>
<string name="uninstall_application_text" msgid="6691975835951187030">"के तपाईँ यो अनुप्रयोग अस्थापना गर्न चाहनु हुन्छ?"</string>
- <string name="uninstall_application_text_all_users" msgid="5574704453233525222">"के तपाईं यो अनुप्रयोग "<b>"सबै"</b>" प्रयोगकर्ताहरूको लागि स्थापना रद्द गर्न चाहनु हुन्छ? अनुप्रयोग र यसको डेटा "<b>"सबै"</b>" प्रयोगकर्ताहरूबाट उपकरणमा हटाइने छ।"</string>
+ <string name="uninstall_application_text_all_users" msgid="5574704453233525222">"के तपाईँ यो अनुप्रयोग "<b>"सबै"</b>" प्रयोगकर्ताहरूको लागि स्थापना रद्द गर्न चाहनु हुन्छ? अनुप्रयोग र यसको डेटा "<b>"सबै"</b>" प्रयोगकर्ताहरूबाट उपकरणमा हटाइने छ।"</string>
<string name="uninstall_application_text_user" msgid="8766882355635485733">"के तपाईँ प्रयोगकर्ता <xliff:g id="USERNAME">%1$s</xliff:g> को लागि यो अनुप्रयोग स्थापना रद्द गर्न चाहनुहुन्छ?"</string>
<string name="uninstall_update_text" msgid="2056387942084605027">"के तपाईँ यस अनुप्रयोगलाई मूल संस्करणसँग फेर्न चाहनु हुन्छ?"</string>
<string name="uninstalling" msgid="5556217435895938250">"अस्थापना गर्दै..."</string>
@@ -86,7 +86,7 @@
<string name="privacyPerms" msgid="1850527049572617">"गोपनीयता"</string>
<string name="devicePerms" msgid="6733560207731294504">"उपकरण पहुँच"</string>
<string name="no_new_perms" msgid="6657813692169565975">"यस अपडेटलाई नयाँ अनुमति आवश्यक पर्दैन।"</string>
- <string name="grant_confirm_question" msgid="4690289297029223742">"के तपाईं निम्न अनुमति प्रदान गर्न चाहनु हुन्छ? यसले पहुँच पाउने छ:"</string>
+ <string name="grant_confirm_question" msgid="4690289297029223742">"के तपाईँ निम्न अनुमति प्रदान गर्न चाहनु हुन्छ? यसले पहुँच पाउने छ:"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"अनुमति दिनुहोस्"</string>
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"अस्वीकार गर्नुहोस्"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g> को <xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>"</string>
@@ -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 72fc07dd..c2c3fe4b 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="2738748390251381682">"Installatieprogramma van pakket"</string>
+ <string name="app_name" msgid="2738748390251381682">"Pakket-installatie"</string>
<string name="next" msgid="3057143178373252333">"Volgende"</string>
<string name="install" msgid="5896438203900042068">"Installeren"</string>
<string name="done" msgid="3889387558374211719">"Gereed"</string>
@@ -88,7 +88,7 @@
<string name="no_new_perms" msgid="6657813692169565975">"Voor deze update zijn geen nieuwe machtigingen vereist."</string>
<string name="grant_confirm_question" msgid="4690289297029223742">"Wilt u de volgende machtigingen verlenen? Hiermee kan toegang worden verkregen tot:"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Toestaan"</string>
- <string name="grant_dialog_button_deny" msgid="2176510645406614340">"Afwijzen"</string>
+ <string name="grant_dialog_button_deny" msgid="2176510645406614340">"Weigeren"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> van <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
<string name="permission_warning_template" msgid="5209102765005869454">"Toestaan dat <xliff:g id="APP_NAME">%1$s</xliff:g> het volgende doet: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Apps"</string>
@@ -109,7 +109,7 @@
<string name="no_apps" msgid="1965493419005012569">"Geen apps"</string>
<string name="location_settings" msgid="1774875730854491297">"Locatie-instellingen"</string>
<string name="location_warning" msgid="8778701356292735971">"<xliff:g id="APP_NAME">%1$s</xliff:g> is een leverancier van locatieservices voor dit apparaat. Locatietoegang kan worden aangepast via de locatie-instellingen."</string>
- <string name="system_warning" msgid="7103819124542305179">"Als u deze toestemming weigert, functioneren basisfuncties van je apparaat mogelijk niet meer zoals bedoeld."</string>
+ <string name="system_warning" msgid="7103819124542305179">"Als je deze toestemming weigert, kan het zijn dat basisfuncties van je apparaat niet meer werken zoals bedoeld."</string>
<string name="permission_summary_enforced_by_policy" msgid="3418617316188986205">"Afgedwongen door beleid"</string>
<string name="loading" msgid="7811651799620593731">"Laden…"</string>
<string name="all_permissions" msgid="5156669007784613042">"Alle rechten"</string>
@@ -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 d6929bd8..be271263 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -102,7 +102,7 @@
<item quantity="other">Jeszcze <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="one">Jeszcze <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
- <string name="old_sdk_deny_warning" msgid="3872277112584842615">"Ta aplikacja jest przeznaczona na straszą wersję Androida. Odmówienie uprawnień może spowodować, że przestanie ona działać w zamierzony sposób."</string>
+ <string name="old_sdk_deny_warning" msgid="3872277112584842615">"Ta aplikacja jest na straszą wersję Androida. Jeśli odmówisz uprawnień, aplikacja może nie działać prawidłowo."</string>
<string name="default_permission_description" msgid="4992892207044156668">"wykonywanie nieznanych działań"</string>
<string name="app_permissions_group_summary" msgid="4787239772223699263">"Dozwolone: <xliff:g id="COUNT_0">%1$d</xliff:g> z <xliff:g id="COUNT_1">%2$d</xliff:g> aplikacji"</string>
<string name="menu_show_system" msgid="6773743421743728921">"Pokaż systemowe"</string>
@@ -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 7fd4f79d..ad029b0d 100644
--- a/res/values-pt-rBR/strings.xml
+++ b/res/values-pt-rBR/strings.xml
@@ -73,7 +73,7 @@
<string name="uninstalling" msgid="5556217435895938250">"Desinstalando..."</string>
<string name="uninstall_done" msgid="3792487853420281888">"Desinstalação concluída."</string>
<string name="uninstall_failed" msgid="631122574306299512">"Desinstalação malsucedida."</string>
- <string name="uninstall_failed_device_policy_manager" msgid="3493789239037852035">"Não é possível desinstalar, pois este pacote é um admin. de dispositivos ativo."</string>
+ <string name="uninstall_failed_device_policy_manager" msgid="3493789239037852035">"Não é possível desinstalar um administrador de dispositivos ativo."</string>
<string name="uninstall_failed_device_policy_manager_of_user" msgid="4466062391552204291">"Não é possível desinstalar este pacote porque ele é um administrador de dispositivo ativo para o usuário <xliff:g id="USERNAME">%1$s</xliff:g>."</string>
<string name="uninstall_blocked_profile_owner" msgid="5397102354360532069">"Este app é necessário para seu perfil de trabalho e não pode ser desinstalado."</string>
<string name="uninstall_blocked_device_owner" msgid="7074175526413453063">"O app é exigido pelo administrador do dispositivo e não pode ser desinstalado."</string>
@@ -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 7fd4f79d..ad029b0d 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -73,7 +73,7 @@
<string name="uninstalling" msgid="5556217435895938250">"Desinstalando..."</string>
<string name="uninstall_done" msgid="3792487853420281888">"Desinstalação concluída."</string>
<string name="uninstall_failed" msgid="631122574306299512">"Desinstalação malsucedida."</string>
- <string name="uninstall_failed_device_policy_manager" msgid="3493789239037852035">"Não é possível desinstalar, pois este pacote é um admin. de dispositivos ativo."</string>
+ <string name="uninstall_failed_device_policy_manager" msgid="3493789239037852035">"Não é possível desinstalar um administrador de dispositivos ativo."</string>
<string name="uninstall_failed_device_policy_manager_of_user" msgid="4466062391552204291">"Não é possível desinstalar este pacote porque ele é um administrador de dispositivo ativo para o usuário <xliff:g id="USERNAME">%1$s</xliff:g>."</string>
<string name="uninstall_blocked_profile_owner" msgid="5397102354360532069">"Este app é necessário para seu perfil de trabalho e não pode ser desinstalado."</string>
<string name="uninstall_blocked_device_owner" msgid="7074175526413453063">"O app é exigido pelo administrador do dispositivo e não pode ser desinstalado."</string>
@@ -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 2a7800ca..1f963c70 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -110,7 +110,7 @@
<string name="no_apps" msgid="1965493419005012569">"Nicio aplicație"</string>
<string name="location_settings" msgid="1774875730854491297">"Setări privind locația"</string>
<string name="location_warning" msgid="8778701356292735971">"<xliff:g id="APP_NAME">%1$s</xliff:g> este un furnizor de servicii de localizare pentru acest dispozitiv. Accesul la locație poate fi modificat din setările privind locația."</string>
- <string name="system_warning" msgid="7103819124542305179">"Dacă refuzați această permisiune, este posibil ca funcțiile de bază ale dispozitivului să nu mai funcționează corespunzător."</string>
+ <string name="system_warning" msgid="7103819124542305179">"Dacă refuzați această permisiune, este posibil ca funcțiile de bază ale dispozitivului să nu mai funcționeze corespunzător."</string>
<string name="permission_summary_enforced_by_policy" msgid="3418617316188986205">"Aplicată conform politicii"</string>
<string name="loading" msgid="7811651799620593731">"Se încarcă..."</string>
<string name="all_permissions" msgid="5156669007784613042">"Toate permisiunile"</string>
@@ -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 21ae1fe6..9cad9cab 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="2738748390251381682">"Программа установки пакета"</string>
+ <string name="app_name" msgid="2738748390251381682">"Установщик пакетов"</string>
<string name="next" msgid="3057143178373252333">"Далее"</string>
<string name="install" msgid="5896438203900042068">"Установить"</string>
<string name="done" msgid="3889387558374211719">"Готово"</string>
@@ -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 86c19317..faef032f 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -36,18 +36,18 @@
<string name="install_failed_inconsistent_certificates" msgid="1517751954440692054">"Det finns redan ett paket med samma namn och en signatur som är i konflikt."</string>
<string name="install_failed_older_sdk" msgid="7947925824732917665">"Paketet fungerar bara med nyare versioner av Android."</string>
<string name="install_failed_cpu_abi_incompatible" product="tablet" msgid="7098684468842750800">"Appen är inte kompatibel med din surfplatta."</string>
- <string name="install_failed_cpu_abi_incompatible" product="tv" msgid="1309625657882930450">"Appen är inte kompatibel med din tv."</string>
+ <string name="install_failed_cpu_abi_incompatible" product="tv" msgid="1309625657882930450">"Appen är inte kompatibel med din TV."</string>
<string name="install_failed_cpu_abi_incompatible" product="default" msgid="4433316303249711331">"Appen är inte kompatibel med din mobil."</string>
<string name="install_failed_file_not_found" msgid="1958430133396322619">"Paketet som angavs togs bort innan installationen var slutförd."</string>
<string name="install_failed_verify_failed" msgid="5567372439890440205">"Paketet klarade inte verifieringen och får inte installeras."</string>
<string name="install_failed_verify_timeout" msgid="7083090219270140373">"En timeout inträffade när paketet skulle verifieras. Prova att installera paketet senare."</string>
<string name="install_failed_msg" product="tablet" msgid="8368835262605608787">"Det gick inte att installera <xliff:g id="APP_NAME">%1$s</xliff:g> på surfplattan."</string>
- <string name="install_failed_msg" product="tv" msgid="3990457938384021566">"<xliff:g id="APP_NAME">%1$s</xliff:g> kunde inte installeras på tv:n."</string>
+ <string name="install_failed_msg" product="tv" msgid="3990457938384021566">"<xliff:g id="APP_NAME">%1$s</xliff:g> kunde inte installeras på TV:n."</string>
<string name="install_failed_msg" product="default" msgid="8554909560982962052">"Det gick inte att installera <xliff:g id="APP_NAME">%1$s</xliff:g> på mobilen."</string>
<string name="launch" msgid="4826921505917605463">"Öppna"</string>
<string name="unknown_apps_dlg_title" msgid="2855558586206583032">"Installation blockerad"</string>
<string name="unknown_apps_dlg_text" product="tablet" msgid="7504186369474734767">"Av säkerhetsskäl går det inte att installera appar från okända källor på din surfplatta."</string>
- <string name="unknown_apps_dlg_text" product="tv" msgid="7195713985140602351">"Tv:n är av säkerhetsskäl inställd på att blockera installationer av appar från okända källor."</string>
+ <string name="unknown_apps_dlg_text" product="tv" msgid="7195713985140602351">"TV:n är av säkerhetsskäl inställd på att blockera installationer av appar från okända källor."</string>
<string name="unknown_apps_dlg_text" product="default" msgid="133213135679009316">"Av säkerhetsskäl går det inte att installera appar från okända källor på din mobil."</string>
<string name="unknown_apps_admin_dlg_text" msgid="1189146324736698462">"Administratören tillåter inte installation av appar från okända källor."</string>
<string name="ok" msgid="3468756155452870475">"OK"</string>
@@ -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 6c16c03d..860e671e 100644
--- a/res/values-ta-rIN/strings.xml
+++ b/res/values-ta-rIN/strings.xml
@@ -90,7 +90,7 @@
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"அனுமதி"</string>
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"நிராகரி"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="5209102765005869454">"<xliff:g id="ACTION">%2$s</xliff:g> செயலுக்கு <xliff:g id="APP_NAME">%1$s</xliff:g>-ஐ அனுமதிக்கவா?"</string>
+ <string name="permission_warning_template" msgid="5209102765005869454">"<xliff:g id="ACTION">%2$s</xliff:g> செயலுக்கு <xliff:g id="APP_NAME">%1$s</xliff:g>ஐ அனுமதிக்கவா?"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"பயன்பாடுகள்"</string>
<string name="app_permissions" msgid="3146758905824597178">"பயன்பாட்டு அனுமதிகள்"</string>
<string name="never_ask_again" msgid="3798895821072102967">"மீண்டும் கேட்காதே"</string>
@@ -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-television/colors.xml b/res/values-television/colors.xml
index eb6bfa7d..08209600 100644
--- a/res/values-television/colors.xml
+++ b/res/values-television/colors.xml
@@ -15,6 +15,13 @@
-->
<resources>
+
+ <color name="lb_content_title_text_color">#FFF1F1F1</color>
+ <color name="lb_content_breadcrumb_text_color">#88F1F1F1</color>
+ <color name="lb_content_description_text_color">#88F1F1F1</color>
+ <color name="lb_action_fragment_background">#FF111111</color>
+ <color name="lb_dialog_activity_background">#77000000</color>
+
<color name="grant_permissions_background_color">#ff263238</color>
<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>
diff --git a/res/values-television/styles.xml b/res/values-television/styles.xml
new file mode 100644
index 00000000..5f712f7d
--- /dev/null
+++ b/res/values-television/styles.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>
+
+ <style name="PreferenceThemeOverlay.v14.Permissions">
+ <item name="preferenceStyle">@style/Preference.Permissions</item>
+ <item name="preferenceCategoryStyle">@style/Preference.Category.Permissions</item>
+ <item name="switchPreferenceStyle">@style/Preference.SwitchPreference.Permissions</item>
+ </style>
+
+ <style name="Preference.Permissions">
+ <item name="layout">@layout/preference_permissions</item>
+ </style>
+
+ <style name="Preference.Category.Permissions">
+ <item name="layout">@layout/preference_category_material</item>
+ </style>
+
+ <style name="Preference.SwitchPreference.Permissions">
+ <item name="layout">@layout/preference_permissions_switch</item>
+ </style>
+
+</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/drawable/header_background.xml b/res/values-watch/integers.xml
index 77db9e03..365ac3ab 100644
--- a/res/drawable/header_background.xml
+++ b/res/values-watch/integers.xml
@@ -14,8 +14,9 @@
limitations under the License.
-->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:attr/colorControlHighlight">
- <item android:drawable="@color/header_background_color" />
-</ripple>
-
+<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 4248b05c..08c9134b 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -92,7 +92,7 @@
<string name="current_permission_template" msgid="6378304249516652817">"第 <xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> 项权限(共 <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g> 项)"</string>
<string name="permission_warning_template" msgid="5209102765005869454">"要允许<xliff:g id="APP_NAME">%1$s</xliff:g><xliff:g id="ACTION">%2$s</xliff:g>吗?"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"应用"</string>
- <string name="app_permissions" msgid="3146758905824597178">"应用所需权限"</string>
+ <string name="app_permissions" msgid="3146758905824597178">"应用访问授权"</string>
<string name="never_ask_again" msgid="3798895821072102967">"不再询问"</string>
<string name="no_permissions" msgid="3210542466245591574">"没有权限"</string>
<string name="additional_permissions" msgid="6667573114240111763">"其他权限"</string>
@@ -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/colors.xml b/res/values/colors.xml
deleted file mode 100755
index 549f55fd..00000000
--- a/res/values/colors.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT 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="shadow">#cc222222</color>
- <color name="transparent">#00000000</color>
- <color name="header_background_color">#ff37474f</color>
- <color name="grant_permissions_app_color">@*android:color/primary_text_default_material_light</color>
- <color name="grant_permissions_progress_color">#60000000</color>
-
- <color name="lb_content_title_text_color">#FFF1F1F1</color>
- <color name="lb_content_breadcrumb_text_color">#88F1F1F1</color>
- <color name="lb_content_description_text_color">#88F1F1F1</color>
- <color name="lb_action_fragment_background">#FF111111</color>
- <color name="lb_dialog_activity_background">#77000000</color>
-
-</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/res/values/styles.xml b/res/values/styles.xml
index 9c166971..7f6a4693 100755
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -15,37 +15,22 @@
-->
<resources>
- <style name="padded">
- <item name="android:paddingStart">16dip</item>
- <item name="android:paddingEnd">16dip</item>
- </style>
- <style name="Theme.DialogWhenLarge" parent="@android:style/Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar"/>
- <style name="Theme.AlertDialogActivity" parent="@android:style/Theme.DeviceDefault.Light.Panel">
- <item name="android:backgroundDimEnabled">true</item>
- </style>
-
- <style name="Theme.Header.Settings" parent="@android:style/Theme.DeviceDefault.Settings">
- </style>
- <style name="PreferenceThemeOverlay.v14.Permissions">
- <item name="preferenceStyle">@style/Preference.Permissions</item>
- <item name="preferenceCategoryStyle">@style/Preference.Category.Permissions</item>
- <item name="switchPreferenceStyle">@style/Preference.SwitchPreference.Permissions</item>
+ <style name="Theme.DialogWhenLarge"
+ parent="@android:style/Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar">
</style>
- <style name="Preference.Permissions">
- <item name="layout">@layout/preference_permissions</item>
- </style>
-
- <style name="Preference.Category.Permissions">
- <item name="layout">@layout/preference_category_material</item>
+ <style name="Theme.AlertDialogActivity"
+ parent="@android:style/Theme.DeviceDefault.Light.Panel">
+ <item name="android:backgroundDimEnabled">true</item>
</style>
- <style name="Preference.SwitchPreference.Permissions">
- <item name="layout">@layout/preference_permissions_switch</item>
+ <style name="Theme.Header.Settings"
+ parent="@android:style/Theme.DeviceDefault.Settings">
</style>
<style name="ActionBar" parent="@android:style/Widget.Material.ActionBar.Solid">
<item name="android:contentInsetStart">72dp</item>
</style>
+
</resources>
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 2f9c2b55..026c77fa 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -16,11 +16,13 @@
-->
<resources>
- <style name="Settings" parent="@android:style/Theme.DeviceDefault.Settings">
- <item name="android:actionBarStyle">@style/ActionBar</item>
- <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Permissions</item>
+
+ <style name="Settings"
+ parent="@android:style/Theme.DeviceDefault.Settings">
</style>
<style name="GrantPermissions"
- parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar" />
+ parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar">
+ </style>
+
</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/PermissionApps.java b/src/com/android/packageinstaller/permission/model/PermissionApps.java
index 9365bf13..e5d96d55 100644
--- a/src/com/android/packageinstaller/permission/model/PermissionApps.java
+++ b/src/com/android/packageinstaller/permission/model/PermissionApps.java
@@ -31,6 +31,7 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
+import com.android.packageinstaller.R;
import com.android.packageinstaller.permission.utils.Utils;
import java.util.ArrayList;
@@ -275,7 +276,7 @@ public class PermissionApps {
if (info.icon != 0) {
mIcon = info.loadUnbadgedIcon(mPm);
} else {
- mIcon = mContext.getDrawable(com.android.internal.R.drawable.ic_perm_device_info);
+ mIcon = mContext.getDrawable(R.drawable.ic_perm_device_info);
}
mIcon = Utils.applyTint(mContext, mIcon, android.R.attr.colorControlNormal);
}
diff --git a/src/com/android/packageinstaller/permission/model/PermissionGroups.java b/src/com/android/packageinstaller/permission/model/PermissionGroups.java
index 59eba856..c496e898 100644
--- a/src/com/android/packageinstaller/permission/model/PermissionGroups.java
+++ b/src/com/android/packageinstaller/permission/model/PermissionGroups.java
@@ -212,11 +212,12 @@ public final class PermissionGroups implements LoaderCallbacks<List<PermissionGr
}
private Drawable loadItemInfoIcon(PackageItemInfo itemInfo) {
- final Drawable icon;
+ Drawable icon = null;
if (itemInfo.icon > 0) {
icon = Utils.loadDrawable(getContext().getPackageManager(),
itemInfo.packageName, itemInfo.icon);
- } else {
+ }
+ if (icon == null) {
icon = getContext().getDrawable(R.drawable.ic_perm_device_info);
}
return icon;
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/ButtonBarLayout.java b/src/com/android/packageinstaller/permission/ui/ButtonBarLayout.java
new file mode 100644
index 00000000..59e54707
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/ButtonBarLayout.java
@@ -0,0 +1,117 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+import com.android.packageinstaller.R;
+
+/**
+ * An extension of LinearLayout that automatically switches to vertical
+ * orientation when it can't fit its child views horizontally.
+ */
+public class ButtonBarLayout extends LinearLayout {
+ /** Whether the current configuration allows stacking. */
+ private boolean mAllowStacking;
+
+ private int mLastWidthSize = -1;
+
+ public ButtonBarLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mAllowStacking = true;
+ }
+
+ public void setAllowStacking(boolean allowStacking) {
+ if (mAllowStacking != allowStacking) {
+ mAllowStacking = allowStacking;
+ if (!mAllowStacking && getOrientation() == LinearLayout.VERTICAL) {
+ setStacked(false);
+ }
+ requestLayout();
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+
+ if (mAllowStacking) {
+ if (widthSize > mLastWidthSize && isStacked()) {
+ // We're being measured wider this time, try un-stacking.
+ setStacked(false);
+ }
+
+ mLastWidthSize = widthSize;
+ }
+
+ boolean needsRemeasure = false;
+
+ // If we're not stacked, make sure the measure spec is AT_MOST rather
+ // than EXACTLY. This ensures that we'll still get TOO_SMALL so that we
+ // know to stack the buttons.
+ final int initialWidthMeasureSpec;
+ if (!isStacked() && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
+ initialWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST);
+
+ // We'll need to remeasure again to fill excess space.
+ needsRemeasure = true;
+ } else {
+ initialWidthMeasureSpec = widthMeasureSpec;
+ }
+
+ super.onMeasure(initialWidthMeasureSpec, heightMeasureSpec);
+
+ if (mAllowStacking && !isStacked()) {
+ final int measuredWidth = getMeasuredWidthAndState();
+ final int measuredWidthState = measuredWidth & MEASURED_STATE_MASK;
+ if (measuredWidthState == MEASURED_STATE_TOO_SMALL) {
+ setStacked(true);
+
+ // Measure again in the new orientation.
+ needsRemeasure = true;
+ }
+ }
+
+ if (needsRemeasure) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+
+ private void setStacked(boolean stacked) {
+ setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
+ setGravity(stacked ? Gravity.RIGHT : Gravity.BOTTOM);
+
+ final View spacer = findViewById(R.id.spacer);
+ if (spacer != null) {
+ spacer.setVisibility(stacked ? View.GONE : View.INVISIBLE);
+ }
+
+ // Reverse the child order. This is specific to the Material button
+ // bar's layout XML and will probably not generalize.
+ final int childCount = getChildCount();
+ for (int i = childCount - 2; i >= 0; i--) {
+ bringChildToFront(getChildAt(i));
+ }
+ }
+
+ private boolean isStacked() {
+ return getOrientation() == LinearLayout.VERTICAL;
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
index 56b3f466..102fd6ef 100644
--- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
+++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
@@ -26,11 +26,12 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PermissionInfo;
import android.content.res.Resources;
+import android.graphics.Typeface;
import android.graphics.drawable.Icon;
import android.hardware.camera2.utils.ArrayUtils;
import android.os.Bundle;
import android.text.SpannableString;
-import android.text.style.ForegroundColorSpan;
+import android.text.style.StyleSpan;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -38,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;
@@ -71,10 +73,14 @@ public class GrantPermissionsActivity extends OverlayTouchActivity
setTitle(R.string.permission_request_title);
- if (Utils.isTelevision(this)) {
- mViewHandler = new GrantPermissionsTvViewHandler(this).setResultListener(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 GrantPermissionsDefaultViewHandler(this).setResultListener(this);
+ mViewHandler = new com.android.packageinstaller.permission.ui.handheld
+ .GrantPermissionsViewHandlerImpl(this).setResultListener(this);
}
mRequestedPermissions = getIntent().getStringArrayExtra(
@@ -206,8 +212,7 @@ public class GrantPermissionsActivity extends OverlayTouchActivity
// Color the app name.
int appLabelStart = message.toString().indexOf(appLabel.toString(), 0);
int appLabelLength = appLabel.length();
- int color = getColor(R.color.grant_permissions_app_color);
- message.setSpan(new ForegroundColorSpan(color), appLabelStart,
+ message.setSpan(new StyleSpan(Typeface.BOLD), appLabelStart,
appLabelStart + appLabelLength, 0);
// Set the new grant view
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsViewHandler.java b/src/com/android/packageinstaller/permission/ui/GrantPermissionsViewHandler.java
index 4032abb2..5e2259af 100644
--- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsViewHandler.java
+++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionsViewHandler.java
@@ -25,7 +25,7 @@ import android.view.WindowManager;
* Class for managing the presentation and user interaction of the "grant
* permissions" user interface.
*/
-interface GrantPermissionsViewHandler {
+public interface GrantPermissionsViewHandler {
/**
* Listener interface for getting notified when the user responds to a
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 8ba6b127..38dbf8f5 100644
--- a/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
+++ b/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
@@ -21,6 +21,9 @@ import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
+import com.android.packageinstaller.permission.ui.wear.AppPermissionsFragmentWear;
+import com.android.packageinstaller.DeviceUtils;
+
public final class ManagePermissionsActivity extends OverlayTouchActivity {
private static final String LOG_TAG = "ManagePermissionsActivity";
@@ -37,7 +40,13 @@ public final class ManagePermissionsActivity extends OverlayTouchActivity {
switch (action) {
case Intent.ACTION_MANAGE_PERMISSIONS: {
- fragment = ManagePermissionsFragment.newInstance();
+ if (DeviceUtils.isTelevision(this)) {
+ fragment = com.android.packageinstaller.permission.ui.television
+ .ManagePermissionsFragment.newInstance();
+ } else {
+ fragment = com.android.packageinstaller.permission.ui.handheld
+ .ManagePermissionsFragment.newInstance();
+ }
} break;
case Intent.ACTION_MANAGE_APP_PERMISSIONS: {
@@ -47,7 +56,15 @@ public final class ManagePermissionsActivity extends OverlayTouchActivity {
finish();
return;
}
- fragment = AppPermissionsFragment.newInstance(packageName);
+ if (DeviceUtils.isWear(this)) {
+ fragment = AppPermissionsFragmentWear.newInstance(packageName);
+ } else if (DeviceUtils.isTelevision(this)) {
+ fragment = com.android.packageinstaller.permission.ui.television
+ .AppPermissionsFragment.newInstance(packageName);
+ } else {
+ fragment = com.android.packageinstaller.permission.ui.handheld
+ .AppPermissionsFragment.newInstance(packageName);
+ }
} break;
case Intent.ACTION_MANAGE_PERMISSION_APPS: {
@@ -57,7 +74,13 @@ public final class ManagePermissionsActivity extends OverlayTouchActivity {
finish();
return;
}
- fragment = PermissionAppsFragment.newInstance(permissionName);
+ if (DeviceUtils.isTelevision(this)) {
+ fragment = com.android.packageinstaller.permission.ui.television
+ .PermissionAppsFragment.newInstance(permissionName);
+ } else {
+ fragment = com.android.packageinstaller.permission.ui.handheld
+ .PermissionAppsFragment.newInstance(permissionName);
+ }
} break;
default: {
diff --git a/src/com/android/packageinstaller/permission/ui/OverlayWarningDialog.java b/src/com/android/packageinstaller/permission/ui/OverlayWarningDialog.java
index a7c1e2a1..61734b47 100644
--- a/src/com/android/packageinstaller/permission/ui/OverlayWarningDialog.java
+++ b/src/com/android/packageinstaller/permission/ui/OverlayWarningDialog.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.packageinstaller.permission.ui;
import android.app.Activity;
diff --git a/src/com/android/packageinstaller/permission/ui/PreferenceImageView.java b/src/com/android/packageinstaller/permission/ui/PreferenceImageView.java
new file mode 100644
index 00000000..c3f51674
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/PreferenceImageView.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.packageinstaller.permission.ui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+/**
+ * Extension of ImageView that correctly applies maxWidth and maxHeight.
+ */
+public class PreferenceImageView extends ImageView {
+
+ public PreferenceImageView(Context context) {
+ this(context, null);
+ }
+
+ public PreferenceImageView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public PreferenceImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public PreferenceImageView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ if (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED) {
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ final int maxWidth = getMaxWidth();
+ if (maxWidth != Integer.MAX_VALUE
+ && (maxWidth < widthSize || widthMode == MeasureSpec.UNSPECIFIED)) {
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST);
+ }
+ }
+
+ final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
+ final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ final int maxHeight = getMaxHeight();
+ if (maxHeight != Integer.MAX_VALUE
+ && (maxHeight < heightSize || heightMode == MeasureSpec.UNSPECIFIED)) {
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
+ }
+ }
+
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/handheld/AllAppPermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/handheld/AllAppPermissionsFragment.java
new file mode 100644
index 00000000..b3b0895c
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/handheld/AllAppPermissionsFragment.java
@@ -0,0 +1,214 @@
+/*
+* 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.handheld;
+
+import android.app.ActionBar;
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceGroup;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.MenuItem;
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.utils.Utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+public final class AllAppPermissionsFragment extends SettingsWithHeader {
+
+ private static final String LOG_TAG = "AllAppPermissionsFragment";
+
+ private static final String KEY_OTHER = "other_perms";
+
+ public static AllAppPermissionsFragment newInstance(String packageName) {
+ AllAppPermissionsFragment instance = new AllAppPermissionsFragment();
+ Bundle arguments = new Bundle();
+ arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
+ instance.setArguments(arguments);
+ return instance;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ final ActionBar ab = getActivity().getActionBar();
+ if (ab != null) {
+ ab.setTitle(R.string.all_permissions);
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ updateUi();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home: {
+ getFragmentManager().popBackStack();
+ return true;
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void updateUi() {
+ if (getPreferenceScreen() != null) {
+ getPreferenceScreen().removeAll();
+ }
+ addPreferencesFromResource(R.xml.all_permissions);
+ PreferenceGroup otherGroup = (PreferenceGroup) findPreference(KEY_OTHER);
+ ArrayList<Preference> prefs = new ArrayList<>(); // Used for sorting.
+ prefs.add(otherGroup);
+ String pkg = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
+ otherGroup.removeAll();
+ PackageManager pm = getContext().getPackageManager();
+
+ try {
+ PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_PERMISSIONS);
+
+ ApplicationInfo appInfo = info.applicationInfo;
+ final Drawable icon = appInfo.loadIcon(pm);
+ final CharSequence label = appInfo.loadLabel(pm);
+ Intent infoIntent = null;
+ if (!getActivity().getIntent().getBooleanExtra(
+ AppPermissionsFragment.EXTRA_HIDE_INFO_BUTTON, false)) {
+ infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
+ .setData(Uri.fromParts("package", pkg, null));
+ }
+ setHeader(icon, label, infoIntent);
+
+ if (info.requestedPermissions != null) {
+ for (int i = 0; i < info.requestedPermissions.length; i++) {
+ PermissionInfo perm;
+ try {
+ perm = pm.getPermissionInfo(info.requestedPermissions[i], 0);
+ } catch (NameNotFoundException e) {
+ Log.e(LOG_TAG,
+ "Can't get permission info for " + info.requestedPermissions[i], e);
+ continue;
+ }
+
+ if ((perm.flags & PermissionInfo.FLAG_INSTALLED) == 0
+ || (perm.flags & PermissionInfo.FLAG_HIDDEN) != 0) {
+ continue;
+ }
+
+ if (perm.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) {
+ PermissionGroupInfo group = getGroup(perm.group, pm);
+ PreferenceGroup pref =
+ findOrCreate(group != null ? group : perm, pm, prefs);
+ pref.addPreference(getPreference(perm, group, pm));
+ } else if (perm.protectionLevel == PermissionInfo.PROTECTION_NORMAL) {
+ PermissionGroupInfo group = getGroup(perm.group, pm);
+ otherGroup.addPreference(getPreference(perm, group, pm));
+ }
+ }
+ }
+ } catch (NameNotFoundException e) {
+ Log.e(LOG_TAG, "Problem getting package info for " + pkg, e);
+ }
+ // Sort an ArrayList of the groups and then set the order from the sorting.
+ Collections.sort(prefs, new Comparator<Preference>() {
+ @Override
+ public int compare(Preference lhs, Preference rhs) {
+ String lKey = lhs.getKey();
+ String rKey = rhs.getKey();
+ if (lKey.equals(KEY_OTHER)) {
+ return 1;
+ } else if (rKey.equals(KEY_OTHER)) {
+ return -1;
+ } else if (Utils.isModernPermissionGroup(lKey)
+ != Utils.isModernPermissionGroup(rKey)) {
+ return Utils.isModernPermissionGroup(lKey) ? -1 : 1;
+ }
+ return lhs.getTitle().toString().compareTo(rhs.getTitle().toString());
+ }
+ });
+ for (int i = 0; i < prefs.size(); i++) {
+ prefs.get(i).setOrder(i);
+ }
+ }
+
+ private PermissionGroupInfo getGroup(String group, PackageManager pm) {
+ try {
+ return pm.getPermissionGroupInfo(group, 0);
+ } catch (NameNotFoundException e) {
+ return null;
+ }
+ }
+
+ private PreferenceGroup findOrCreate(PackageItemInfo group, PackageManager pm,
+ ArrayList<Preference> prefs) {
+ PreferenceGroup pref = (PreferenceGroup) findPreference(group.name);
+ if (pref == null) {
+ pref = new PreferenceCategory(getContext());
+ pref.setKey(group.name);
+ pref.setTitle(group.loadLabel(pm));
+ prefs.add(pref);
+ getPreferenceScreen().addPreference(pref);
+ }
+ return pref;
+ }
+
+ private Preference getPreference(PermissionInfo perm, PermissionGroupInfo group,
+ PackageManager pm) {
+ Preference pref = new Preference(getContext());
+ Drawable icon = null;
+ if (perm.icon != 0) {
+ icon = perm.loadIcon(pm);
+ } else if (group != null && group.icon != 0) {
+ icon = group.loadIcon(pm);
+ } else {
+ icon = getContext().getDrawable(R.drawable.ic_perm_device_info);
+ }
+ pref.setIcon(Utils.applyTint(getContext(), icon, android.R.attr.colorControlNormal));
+ pref.setTitle(perm.loadLabel(pm));
+ final CharSequence desc = perm.loadDescription(pm);
+ pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ new AlertDialog.Builder(getContext())
+ .setMessage(desc)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ return true;
+ }
+ });
+
+ return pref;
+ }
+} \ No newline at end of file
diff --git a/src/com/android/packageinstaller/permission/ui/handheld/AppPermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/handheld/AppPermissionsFragment.java
new file mode 100644
index 00000000..f56cba70
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/handheld/AppPermissionsFragment.java
@@ -0,0 +1,404 @@
+/*
+* 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.handheld;
+
+import android.annotation.Nullable;
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+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.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 AppPermissionsFragment extends SettingsWithHeader
+ implements OnPreferenceChangeListener {
+
+ private static final String LOG_TAG = "ManagePermsFragment";
+
+ static final String EXTRA_HIDE_INFO_BUTTON = "hideInfoButton";
+
+ private static final int MENU_ALL_PERMS = 0;
+
+ private List<AppPermissionGroup> mToggledGroups;
+ private AppPermissions mAppPermissions;
+ private PreferenceScreen mExtraScreen;
+
+ private boolean mHasConfirmedRevoke;
+
+ public static AppPermissionsFragment newInstance(String packageName) {
+ return setPackageName(new AppPermissionsFragment(), 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);
+ setLoading(true /* loading */, false /* animate */);
+ setHasOptionsMenu(true);
+ final ActionBar ab = getActivity().getActionBar();
+ if (ab != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+
+ String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
+ Activity activity = getActivity();
+ PackageInfo packageInfo = getPackageInfo(activity, packageName);
+ 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();
+ }
+ });
+ loadPreferences();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mAppPermissions.refresh();
+ setPreferencesCheckedState();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home: {
+ getActivity().finish();
+ return true;
+ }
+
+ case MENU_ALL_PERMS: {
+ Fragment frag = AllAppPermissionsFragment.newInstance(
+ getArguments().getString(Intent.EXTRA_PACKAGE_NAME));
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, frag)
+ .addToBackStack("AllPerms")
+ .commit();
+ return true;
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ if (mAppPermissions != null) {
+ bindUi(this, mAppPermissions.getPackageInfo());
+ }
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ menu.add(Menu.NONE, MENU_ALL_PERMS, Menu.NONE, R.string.all_permissions);
+ }
+
+ private static void bindUi(SettingsWithHeader fragment, PackageInfo packageInfo) {
+ Activity activity = fragment.getActivity();
+ PackageManager pm = activity.getPackageManager();
+ ApplicationInfo appInfo = packageInfo.applicationInfo;
+ Intent infoIntent = null;
+ if (!activity.getIntent().getBooleanExtra(EXTRA_HIDE_INFO_BUTTON, false)) {
+ infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
+ .setData(Uri.fromParts("package", packageInfo.packageName, null));
+ }
+
+ Drawable icon = appInfo.loadIcon(pm);
+ CharSequence label = appInfo.loadLabel(pm);
+ fragment.setHeader(icon, label, infoIntent);
+
+ ActionBar ab = activity.getActionBar();
+ if (ab != null) {
+ ab.setTitle(R.string.app_permissions);
+ }
+
+ ViewGroup rootView = (ViewGroup) fragment.getView();
+ ImageView iconView = (ImageView) rootView.findViewById(R.id.lb_icon);
+ if (iconView != null) {
+ iconView.setImageDrawable(icon);
+ }
+ TextView titleView = (TextView) rootView.findViewById(R.id.lb_title);
+ if (titleView != null) {
+ titleView.setText(R.string.app_permissions);
+ }
+ TextView breadcrumbView = (TextView) rootView.findViewById(R.id.lb_breadcrumb);
+ if (breadcrumbView != null) {
+ breadcrumbView.setText(label);
+ }
+ }
+
+ private void loadPreferences() {
+ Context context = getActivity();
+ if (context == null) {
+ return;
+ }
+
+ PreferenceScreen screen = getPreferenceScreen();
+ if (screen == null) {
+ screen = getPreferenceManager().createPreferenceScreen(getActivity());
+ setPreferenceScreen(screen);
+ }
+
+ screen.removeAll();
+
+ if (mExtraScreen != null) {
+ mExtraScreen.removeAll();
+ }
+
+ final Preference extraPerms = new Preference(context);
+ extraPerms.setIcon(R.drawable.ic_toc);
+ extraPerms.setTitle(R.string.additional_permissions);
+
+ for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) {
+ if (!Utils.shouldShowPermission(group, mAppPermissions.getPackageInfo().packageName)) {
+ continue;
+ }
+
+ boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG);
+
+ SwitchPreference preference = new SwitchPreference(context);
+ preference.setOnPreferenceChangeListener(this);
+ preference.setKey(group.getName());
+ Drawable icon = Utils.loadDrawable(context.getPackageManager(),
+ group.getIconPkg(), group.getIconResId());
+ preference.setIcon(Utils.applyTint(getContext(), icon,
+ android.R.attr.colorControlNormal));
+ preference.setTitle(group.getLabel());
+ if (group.isPolicyFixed()) {
+ preference.setSummary(getString(R.string.permission_summary_enforced_by_policy));
+ }
+ preference.setPersistent(false);
+ preference.setEnabled(!group.isPolicyFixed());
+ preference.setChecked(group.areRuntimePermissionsGranted());
+
+ if (isPlatform) {
+ screen.addPreference(preference);
+ } else {
+ if (mExtraScreen == null) {
+ mExtraScreen = getPreferenceManager().createPreferenceScreen(context);
+ }
+ mExtraScreen.addPreference(preference);
+ }
+ }
+
+ if (mExtraScreen != null) {
+ extraPerms.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ AdditionalPermissionsFragment frag = new AdditionalPermissionsFragment();
+ setPackageName(frag, getArguments().getString(Intent.EXTRA_PACKAGE_NAME));
+ frag.setTargetFragment(AppPermissionsFragment.this, 0);
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, frag)
+ .addToBackStack(null)
+ .commit();
+ return true;
+ }
+ });
+ int count = mExtraScreen.getPreferenceCount();
+ extraPerms.setSummary(getResources().getQuantityString(
+ R.plurals.additional_permissions_more, count, count));
+ screen.addPreference(extraPerms);
+ }
+
+ setLoading(false /* loading */, true /* animate */);
+ }
+
+ @Override
+ public boolean onPreferenceChange(final Preference preference, Object newValue) {
+ String groupName = preference.getKey();
+ final AppPermissionGroup group = mAppPermissions.getPermissionGroup(groupName);
+
+ if (group == null) {
+ return false;
+ }
+
+ OverlayTouchActivity activity = (OverlayTouchActivity) getActivity();
+ if (activity.isObscuredTouch()) {
+ activity.showOverlayDialog();
+ return false;
+ }
+
+ addToggledGroup(group);
+
+ if (LocationUtils.isLocationGroupAndProvider(group.getName(), group.getApp().packageName)) {
+ LocationUtils.showLocationDialog(getContext(), mAppPermissions.getAppLabel());
+ return false;
+ }
+ if (newValue == Boolean.TRUE) {
+ group.grantRuntimePermissions(false);
+ } else {
+ final boolean grantedByDefault = group.hasGrantedByDefaultPermission();
+ if (grantedByDefault || (!group.hasRuntimePermission() && !mHasConfirmedRevoke)) {
+ new AlertDialog.Builder(getContext())
+ .setMessage(grantedByDefault ? R.string.system_warning
+ : R.string.old_sdk_deny_warning)
+ .setNegativeButton(R.string.cancel, null)
+ .setPositiveButton(R.string.grant_dialog_button_deny,
+ new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ((SwitchPreference) preference).setChecked(false);
+ group.revokeRuntimePermissions(false);
+ if (!grantedByDefault) {
+ mHasConfirmedRevoke = true;
+ }
+ }
+ })
+ .show();
+ return false;
+ } else {
+ group.revokeRuntimePermissions(false);
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ logToggledGroups();
+ }
+
+ 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 logToggledGroups() {
+ if (mToggledGroups != null) {
+ String packageName = mAppPermissions.getPackageInfo().packageName;
+ SafetyNetLogger.logPermissionsToggled(packageName, mToggledGroups);
+ mToggledGroups = null;
+ }
+ }
+
+ private void setPreferencesCheckedState() {
+ setPreferencesCheckedState(getPreferenceScreen());
+ if (mExtraScreen != null) {
+ setPreferencesCheckedState(mExtraScreen);
+ }
+ }
+
+ private void setPreferencesCheckedState(PreferenceScreen screen) {
+ int preferenceCount = screen.getPreferenceCount();
+ for (int i = 0; i < preferenceCount; i++) {
+ Preference preference = screen.getPreference(i);
+ if (preference instanceof SwitchPreference) {
+ SwitchPreference switchPref = (SwitchPreference) preference;
+ AppPermissionGroup group = mAppPermissions.getPermissionGroup(switchPref.getKey());
+ if (group != null) {
+ switchPref.setChecked(group.areRuntimePermissionsGranted());
+ }
+ }
+ }
+ }
+
+ private static PackageInfo getPackageInfo(Activity activity, String packageName) {
+ try {
+ return activity.getPackageManager().getPackageInfo(
+ packageName, PackageManager.GET_PERMISSIONS);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e);
+ return null;
+ }
+ }
+
+ public static class AdditionalPermissionsFragment extends SettingsWithHeader {
+ AppPermissionsFragment mOuterFragment;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ mOuterFragment = (AppPermissionsFragment) getTargetFragment();
+ super.onCreate(savedInstanceState);
+ setHeader(mOuterFragment.mIcon, mOuterFragment.mLabel, mOuterFragment.mInfoIntent);
+ setHasOptionsMenu(true);
+ setPreferenceScreen(mOuterFragment.mExtraScreen);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
+ bindUi(this, getPackageInfo(getActivity(), packageName));
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ getFragmentManager().popBackStack();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsDefaultViewHandler.java b/src/com/android/packageinstaller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.java
index c5d78784..2d27f069 100644
--- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsDefaultViewHandler.java
+++ b/src/com/android/packageinstaller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.packageinstaller.permission.ui;
+package com.android.packageinstaller.permission.ui.handheld;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -40,12 +40,14 @@ import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
-import com.android.internal.widget.ButtonBarLayout;
import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.ui.ButtonBarLayout;
+import com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler;
+import com.android.packageinstaller.permission.ui.ManualLayoutFrame;
import java.util.ArrayList;
-final class GrantPermissionsDefaultViewHandler
+public final class GrantPermissionsViewHandlerImpl
implements GrantPermissionsViewHandler, OnClickListener {
public static final String ARG_GROUP_NAME = "ARG_GROUP_NAME";
@@ -101,12 +103,12 @@ final class GrantPermissionsDefaultViewHandler
}
};
- GrantPermissionsDefaultViewHandler(Context context) {
+ public GrantPermissionsViewHandlerImpl(Context context) {
mContext = context;
}
@Override
- public GrantPermissionsDefaultViewHandler setResultListener(ResultListener listener) {
+ public GrantPermissionsViewHandlerImpl setResultListener(ResultListener listener) {
mResultListener = listener;
return this;
}
@@ -314,9 +316,7 @@ final class GrantPermissionsDefaultViewHandler
public View createView() {
mRootView = (ManualLayoutFrame) LayoutInflater.from(mContext)
.inflate(R.layout.grant_permissions, null);
- ((ButtonBarLayout) mRootView.findViewById(R.id.button_group)).setAllowStacking(
- Resources.getSystem().getBoolean(
- com.android.internal.R.bool.allow_stacked_button_bar));
+ ((ButtonBarLayout) mRootView.findViewById(R.id.button_group)).setAllowStacking(true);
mDialogContainer = (ViewGroup) mRootView.findViewById(R.id.dialog_container);
mMessageView = (TextView) mRootView.findViewById(R.id.permission_message);
diff --git a/src/com/android/packageinstaller/permission/ui/handheld/ManagePermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/handheld/ManagePermissionsFragment.java
new file mode 100644
index 00000000..c53da879
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/handheld/ManagePermissionsFragment.java
@@ -0,0 +1,268 @@
+/*
+ * 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.handheld;
+
+import android.annotation.Nullable;
+import android.app.ActionBar;
+import android.app.FragmentTransaction;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceScreen;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.model.PermissionApps;
+import com.android.packageinstaller.permission.model.PermissionApps.PmCache;
+import com.android.packageinstaller.permission.model.PermissionGroup;
+import com.android.packageinstaller.permission.model.PermissionGroups;
+import com.android.packageinstaller.permission.utils.Utils;
+
+import java.util.List;
+
+public final class ManagePermissionsFragment extends PermissionsFrameFragment
+ implements PermissionGroups.PermissionsGroupsChangeCallback,
+ Preference.OnPreferenceClickListener {
+ private static final String LOG_TAG = "ManagePermissionsFragment";
+
+ private static final String OS_PKG = "android";
+
+ private static final String EXTRA_PREFS_KEY = "extra_prefs_key";
+
+ private ArraySet<String> mLauncherPkgs;
+
+ private PermissionGroups mPermissions;
+
+ private PreferenceScreen mExtraScreen;
+
+ public static ManagePermissionsFragment newInstance() {
+ return new ManagePermissionsFragment();
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setLoading(true /* loading */, false /* animate */);
+ setHasOptionsMenu(true);
+ final ActionBar ab = getActivity().getActionBar();
+ if (ab != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+ mLauncherPkgs = Utils.getLauncherPackages(getContext());
+ mPermissions = new PermissionGroups(getActivity(), getLoaderManager(), this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mPermissions.refresh();
+ updatePermissionsUi();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ getActivity().finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ String key = preference.getKey();
+
+ PermissionGroup group = mPermissions.getGroup(key);
+ if (group == null) {
+ return false;
+ }
+
+ Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSION_APPS)
+ .putExtra(Intent.EXTRA_PERMISSION_NAME, key);
+ try {
+ getActivity().startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.w(LOG_TAG, "No app to handle " + intent);
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onPermissionGroupsChanged() {
+ updatePermissionsUi();
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ bindPermissionUi(getActivity(), getView());
+ }
+
+ private static void bindPermissionUi(@Nullable Context context, @Nullable View rootView) {
+ if (context == null || rootView == null) {
+ return;
+ }
+
+ ImageView iconView = (ImageView) rootView.findViewById(R.id.lb_icon);
+ if (iconView != null) {
+ // Set the icon as the background instead of the image because ImageView
+ // doesn't properly scale vector drawables beyond their intrinsic size
+ Drawable icon = context.getDrawable(R.drawable.ic_lock);
+ icon.setTint(context.getColor(R.color.off_white));
+ iconView.setBackground(icon);
+ }
+ TextView titleView = (TextView) rootView.findViewById(R.id.lb_title);
+ if (titleView != null) {
+ titleView.setText(R.string.app_permissions);
+ }
+ TextView breadcrumbView = (TextView) rootView.findViewById(R.id.lb_breadcrumb);
+ if (breadcrumbView != null) {
+ breadcrumbView.setText(R.string.app_permissions_breadcrumb);
+ }
+ }
+
+ private void updatePermissionsUi() {
+ Context context = getActivity();
+ if (context == null) {
+ return;
+ }
+
+ List<PermissionGroup> groups = mPermissions.getGroups();
+ PreferenceScreen screen = getPreferenceScreen();
+ if (screen == null) {
+ screen = getPreferenceManager().createPreferenceScreen(getActivity());
+ setPreferenceScreen(screen);
+ }
+
+ // Use this to speed up getting the info for all of the PermissionApps below.
+ // Create a new one for each refresh to make sure it has fresh data.
+ PmCache cache = new PmCache(getContext().getPackageManager());
+ for (PermissionGroup group : groups) {
+ boolean isSystemPermission = group.getDeclaringPackage().equals(OS_PKG);
+
+ Preference preference = findPreference(group.getName());
+ if (preference == null && mExtraScreen != null) {
+ preference = mExtraScreen.findPreference(group.getName());
+ }
+ if (preference == null) {
+ preference = new Preference(context);
+ preference.setOnPreferenceClickListener(this);
+ preference.setKey(group.getName());
+ preference.setIcon(Utils.applyTint(context, group.getIcon(),
+ android.R.attr.colorControlNormal));
+ preference.setTitle(group.getLabel());
+ // Set blank summary so that no resizing/jumping happens when the summary is loaded.
+ preference.setSummary(" ");
+ preference.setPersistent(false);
+ if (isSystemPermission) {
+ screen.addPreference(preference);
+ } else {
+ if (mExtraScreen == null) {
+ mExtraScreen = getPreferenceManager().createPreferenceScreen(context);
+ }
+ mExtraScreen.addPreference(preference);
+ }
+ }
+ final Preference finalPref = preference;
+
+ new PermissionApps(getContext(), group.getName(), new PermissionApps.Callback() {
+ @Override
+ public void onPermissionsLoaded(PermissionApps permissionApps) {
+ if (getActivity() == null) {
+ return;
+ }
+ int granted = permissionApps.getGrantedCount(mLauncherPkgs);
+ int total = permissionApps.getTotalCount(mLauncherPkgs);
+ finalPref.setSummary(getString(R.string.app_permissions_group_summary,
+ granted, total));
+ }
+ }, cache).refresh(false);
+ }
+
+ if (mExtraScreen != null && mExtraScreen.getPreferenceCount() > 0
+ && screen.findPreference(EXTRA_PREFS_KEY) == null) {
+ Preference extraScreenPreference = new Preference(context);
+ extraScreenPreference.setKey(EXTRA_PREFS_KEY);
+ extraScreenPreference.setIcon(Utils.applyTint(context,
+ R.drawable.ic_more_items,
+ android.R.attr.colorControlNormal));
+ extraScreenPreference.setTitle(R.string.additional_permissions);
+ extraScreenPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ AdditionalPermissionsFragment frag = new AdditionalPermissionsFragment();
+ frag.setTargetFragment(ManagePermissionsFragment.this, 0);
+ FragmentTransaction ft = getFragmentManager().beginTransaction();
+ ft.replace(android.R.id.content, frag);
+ ft.addToBackStack(null);
+ ft.commit();
+ return true;
+ }
+ });
+ int count = mExtraScreen.getPreferenceCount();
+ extraScreenPreference.setSummary(getResources().getQuantityString(
+ R.plurals.additional_permissions_more, count, count));
+ screen.addPreference(extraScreenPreference);
+ }
+ if (screen.getPreferenceCount() != 0) {
+ setLoading(false /* loading */, true /* animate */);
+ }
+ }
+
+ public static class AdditionalPermissionsFragment extends PermissionsFrameFragment {
+ @Override
+ public void onCreate(Bundle icicle) {
+ setLoading(true /* loading */, false /* animate */);
+ super.onCreate(icicle);
+ getActivity().setTitle(R.string.additional_permissions);
+ setHasOptionsMenu(true);
+
+ setPreferenceScreen(((ManagePermissionsFragment) getTargetFragment()).mExtraScreen);
+ setLoading(false /* loading */, true /* animate */);
+ }
+
+ @Override
+ public void onDestroy() {
+ getActivity().setTitle(R.string.app_permissions);
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ getFragmentManager().popBackStack();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ bindPermissionUi(getActivity(), getView());
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java b/src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java
new file mode 100644
index 00000000..eee2f716
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java
@@ -0,0 +1,428 @@
+/*
+ * 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.handheld;
+
+import android.app.ActionBar;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+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;
+import com.android.packageinstaller.permission.model.PermissionApps.Callback;
+import com.android.packageinstaller.permission.model.PermissionApps.PermissionApp;
+import com.android.packageinstaller.permission.ui.OverlayTouchActivity;
+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 PermissionAppsFragment extends PermissionsFrameFragment implements Callback,
+ Preference.OnPreferenceChangeListener {
+
+ private static final int MENU_SHOW_SYSTEM = Menu.FIRST;
+ private static final int MENU_HIDE_SYSTEM = Menu.FIRST + 1;
+ private static final String KEY_SHOW_SYSTEM_PREFS = "_showSystem";
+
+ public static PermissionAppsFragment newInstance(String permissionName) {
+ return setPermissionName(new PermissionAppsFragment(), permissionName);
+ }
+
+ private static <T extends Fragment> T setPermissionName(T fragment, String permissionName) {
+ Bundle arguments = new Bundle();
+ arguments.putString(Intent.EXTRA_PERMISSION_NAME, permissionName);
+ fragment.setArguments(arguments);
+ return fragment;
+ }
+
+ private PermissionApps mPermissionApps;
+
+ private PreferenceScreen mExtraScreen;
+
+ private ArrayMap<String, AppPermissionGroup> mToggledGroups;
+ private ArraySet<String> mLauncherPkgs;
+ private boolean mHasConfirmedRevoke;
+
+ private boolean mShowSystem;
+ private MenuItem mShowSystemMenu;
+ private MenuItem mHideSystemMenu;
+
+ private Callback mOnPermissionsLoadedListener;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setLoading(true /* loading */, false /* animate */);
+ setHasOptionsMenu(true);
+ final ActionBar ab = getActivity().getActionBar();
+ if (ab != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+ mLauncherPkgs = Utils.getLauncherPackages(getContext());
+
+ String groupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME);
+ mPermissionApps = new PermissionApps(getActivity(), groupName, this);
+ mPermissionApps.refresh(true);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mPermissionApps.refresh(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ mShowSystemMenu = menu.add(Menu.NONE, MENU_SHOW_SYSTEM, Menu.NONE,
+ R.string.menu_show_system);
+ mHideSystemMenu = menu.add(Menu.NONE, MENU_HIDE_SYSTEM, Menu.NONE,
+ R.string.menu_hide_system);
+ updateMenu();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ getActivity().finish();
+ return true;
+ case MENU_SHOW_SYSTEM:
+ case MENU_HIDE_SYSTEM:
+ mShowSystem = item.getItemId() == MENU_SHOW_SYSTEM;
+ if (mPermissionApps.getApps() != null) {
+ onPermissionsLoaded(mPermissionApps);
+ }
+ updateMenu();
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void updateMenu() {
+ mShowSystemMenu.setVisible(!mShowSystem);
+ mHideSystemMenu.setVisible(mShowSystem);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ bindUi(this, mPermissionApps);
+ }
+
+ private static void bindUi(Fragment fragment, PermissionApps permissionApps) {
+ final Drawable icon = permissionApps.getIcon();
+ final CharSequence label = permissionApps.getLabel();
+ final ActionBar ab = fragment.getActivity().getActionBar();
+ if (ab != null) {
+ ab.setTitle(fragment.getString(R.string.permission_title, label));
+ }
+
+ final ViewGroup rootView = (ViewGroup) fragment.getView();
+ final ImageView iconView = (ImageView) rootView.findViewById(R.id.lb_icon);
+ if (iconView != null) {
+ // Set the icon as the background instead of the image because ImageView
+ // doesn't properly scale vector drawables beyond their intrinsic size
+ iconView.setBackground(icon);
+ }
+ final TextView titleView = (TextView) rootView.findViewById(R.id.lb_title);
+ if (titleView != null) {
+ titleView.setText(label);
+ }
+ final TextView breadcrumbView = (TextView) rootView.findViewById(R.id.lb_breadcrumb);
+ if (breadcrumbView != null) {
+ breadcrumbView.setText(R.string.app_permissions);
+ }
+ }
+
+ private void setOnPermissionsLoadedListener(Callback callback) {
+ mOnPermissionsLoadedListener = callback;
+ }
+
+ @Override
+ public void onPermissionsLoaded(PermissionApps permissionApps) {
+ Context context = getActivity();
+
+ if (context == null) {
+ return;
+ }
+
+ boolean isTelevision = DeviceUtils.isTelevision(context);
+ PreferenceScreen screen = getPreferenceScreen();
+ if (screen == null) {
+ screen = getPreferenceManager().createPreferenceScreen(getActivity());
+ setPreferenceScreen(screen);
+ }
+
+ ArraySet<String> preferencesToRemove = new ArraySet<>();
+ for (int i = 0, n = screen.getPreferenceCount(); i < n; i++) {
+ preferencesToRemove.add(screen.getPreference(i).getKey());
+ }
+ if (mExtraScreen != null) {
+ for (int i = 0, n = mExtraScreen.getPreferenceCount(); i < n; i++) {
+ preferencesToRemove.add(mExtraScreen.getPreference(i).getKey());
+ }
+ }
+
+ for (PermissionApp app : permissionApps.getApps()) {
+ if (!Utils.shouldShowPermission(app)) {
+ continue;
+ }
+
+ String key = app.getKey();
+ preferencesToRemove.remove(key);
+ Preference existingPref = screen.findPreference(key);
+ if (existingPref == null && mExtraScreen != null) {
+ existingPref = mExtraScreen.findPreference(key);
+ }
+
+ boolean isSystemApp = Utils.isSystem(app, mLauncherPkgs);
+ if (isSystemApp && !isTelevision && !mShowSystem) {
+ if (existingPref != null) {
+ screen.removePreference(existingPref);
+ }
+ continue;
+ }
+
+ if (existingPref != null) {
+ // If existing preference - only update its state.
+ if (app.isPolicyFixed()) {
+ existingPref.setSummary(getString(
+ R.string.permission_summary_enforced_by_policy));
+ }
+ existingPref.setPersistent(false);
+ existingPref.setEnabled(!app.isPolicyFixed());
+ if (existingPref instanceof SwitchPreference) {
+ ((SwitchPreference) existingPref)
+ .setChecked(app.areRuntimePermissionsGranted());
+ }
+ continue;
+ }
+
+ SwitchPreference pref = new SwitchPreference(context);
+ pref.setOnPreferenceChangeListener(this);
+ pref.setKey(app.getKey());
+ pref.setIcon(app.getIcon());
+ pref.setTitle(app.getLabel());
+ if (app.isPolicyFixed()) {
+ pref.setSummary(getString(R.string.permission_summary_enforced_by_policy));
+ }
+ pref.setPersistent(false);
+ pref.setEnabled(!app.isPolicyFixed());
+ pref.setChecked(app.areRuntimePermissionsGranted());
+
+ if (isSystemApp && isTelevision) {
+ if (mExtraScreen == null) {
+ mExtraScreen = getPreferenceManager().createPreferenceScreen(context);
+ }
+ mExtraScreen.addPreference(pref);
+ } else {
+ screen.addPreference(pref);
+ }
+ }
+
+ if (mExtraScreen != null) {
+ preferencesToRemove.remove(KEY_SHOW_SYSTEM_PREFS);
+ Preference pref = screen.findPreference(KEY_SHOW_SYSTEM_PREFS);
+
+ if (pref == null) {
+ pref = new Preference(context);
+ pref.setKey(KEY_SHOW_SYSTEM_PREFS);
+ pref.setIcon(Utils.applyTint(context, R.drawable.ic_toc,
+ android.R.attr.colorControlNormal));
+ pref.setTitle(R.string.preference_show_system_apps);
+ pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ SystemAppsFragment frag = new SystemAppsFragment();
+ setPermissionName(frag, getArguments().getString(Intent.EXTRA_PERMISSION_NAME));
+ frag.setTargetFragment(PermissionAppsFragment.this, 0);
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, frag)
+ .addToBackStack("SystemApps")
+ .commit();
+ return true;
+ }
+ });
+ screen.addPreference(pref);
+ }
+
+ int grantedCount = 0;
+ for (int i = 0, n = mExtraScreen.getPreferenceCount(); i < n; i++) {
+ if (((SwitchPreference) mExtraScreen.getPreference(i)).isChecked()) {
+ grantedCount++;
+ }
+ }
+ pref.setSummary(getString(R.string.app_permissions_group_summary,
+ grantedCount, mExtraScreen.getPreferenceCount()));
+ }
+
+ for (String key : preferencesToRemove) {
+ Preference pref = screen.findPreference(key);
+ if (pref != null) {
+ screen.removePreference(pref);
+ } else if (mExtraScreen != null) {
+ pref = mExtraScreen.findPreference(key);
+ if (pref != null) {
+ mExtraScreen.removePreference(pref);
+ }
+ }
+ }
+
+ setLoading(false /* loading */, true /* animate */);
+
+ if (mOnPermissionsLoadedListener != null) {
+ mOnPermissionsLoadedListener.onPermissionsLoaded(permissionApps);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceChange(final Preference preference, Object newValue) {
+ String pkg = preference.getKey();
+ final PermissionApp app = mPermissionApps.getApp(pkg);
+
+ if (app == null) {
+ return false;
+ }
+
+ OverlayTouchActivity activity = (OverlayTouchActivity) getActivity();
+ if (activity.isObscuredTouch()) {
+ activity.showOverlayDialog();
+ return false;
+ }
+
+ addToggledGroup(app.getPackageName(), app.getPermissionGroup());
+
+ if (LocationUtils.isLocationGroupAndProvider(mPermissionApps.getGroupName(),
+ app.getPackageName())) {
+ LocationUtils.showLocationDialog(getContext(), app.getLabel());
+ return false;
+ }
+ if (newValue == Boolean.TRUE) {
+ app.grantRuntimePermissions();
+ } else {
+ final boolean grantedByDefault = app.hasGrantedByDefaultPermissions();
+ if (grantedByDefault || (!app.hasRuntimePermissions() && !mHasConfirmedRevoke)) {
+ new AlertDialog.Builder(getContext())
+ .setMessage(grantedByDefault ? R.string.system_warning
+ : R.string.old_sdk_deny_warning)
+ .setNegativeButton(R.string.cancel, null)
+ .setPositiveButton(R.string.grant_dialog_button_deny,
+ new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ((SwitchPreference) preference).setChecked(false);
+ app.revokeRuntimePermissions();
+ if (!grantedByDefault) {
+ mHasConfirmedRevoke = true;
+ }
+ }
+ })
+ .show();
+ return false;
+ } else {
+ app.revokeRuntimePermissions();
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ logToggledGroups();
+ }
+
+ private void addToggledGroup(String packageName, AppPermissionGroup group) {
+ if (mToggledGroups == null) {
+ mToggledGroups = new ArrayMap<>();
+ }
+ // Double toggle is back to initial state.
+ if (mToggledGroups.containsKey(packageName)) {
+ mToggledGroups.remove(packageName);
+ } else {
+ mToggledGroups.put(packageName, group);
+ }
+ }
+
+ private void logToggledGroups() {
+ if (mToggledGroups != null) {
+ final int groupCount = mToggledGroups.size();
+ for (int i = 0; i < groupCount; i++) {
+ String packageName = mToggledGroups.keyAt(i);
+ List<AppPermissionGroup> groups = new ArrayList<>();
+ groups.add(mToggledGroups.valueAt(i));
+ SafetyNetLogger.logPermissionsToggled(packageName, groups);
+ }
+ mToggledGroups = null;
+ }
+ }
+
+ public static class SystemAppsFragment extends PermissionsFrameFragment implements Callback {
+ PermissionAppsFragment mOuterFragment;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ mOuterFragment = (PermissionAppsFragment) getTargetFragment();
+ setLoading(true /* loading */, false /* animate */);
+ super.onCreate(savedInstanceState);
+ if (mOuterFragment.mExtraScreen != null) {
+ setPreferenceScreen();
+ } else {
+ mOuterFragment.setOnPermissionsLoadedListener(this);
+ }
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ String groupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME);
+ PermissionApps permissionApps = new PermissionApps(getActivity(), groupName, null);
+ bindUi(this, permissionApps);
+ }
+
+ @Override
+ public void onPermissionsLoaded(PermissionApps permissionApps) {
+ setPreferenceScreen();
+ mOuterFragment.setOnPermissionsLoadedListener(null);
+ }
+
+ private void setPreferenceScreen() {
+ setPreferenceScreen(mOuterFragment.mExtraScreen);
+ setLoading(false /* loading */, true /* animate */);
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/handheld/PermissionsFrameFragment.java b/src/com/android/packageinstaller/permission/ui/handheld/PermissionsFrameFragment.java
new file mode 100644
index 00000000..e7f63b23
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/handheld/PermissionsFrameFragment.java
@@ -0,0 +1,121 @@
+/*
+ * 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.handheld;
+
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
+import android.widget.ListView;
+import android.widget.TextView;
+import com.android.packageinstaller.R;
+
+public abstract class PermissionsFrameFragment extends PreferenceFragment {
+ private ViewGroup mPreferencesContainer;
+
+ private View mLoadingView;
+ private ViewGroup mPrefsView;
+ private boolean mIsLoading;
+
+ /**
+ * Returns the view group that holds the preferences objects. This will
+ * only be set after {@link #onCreateView} has been called.
+ */
+ protected final ViewGroup getPreferencesContainer() {
+ return mPreferencesContainer;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.permissions_frame, container,
+ false);
+ mPrefsView = (ViewGroup) rootView.findViewById(R.id.prefs_container);
+ if (mPrefsView == null) {
+ mPrefsView = rootView;
+ }
+ mLoadingView = rootView.findViewById(R.id.loading_container);
+ mPreferencesContainer = (ViewGroup) super.onCreateView(
+ inflater, mPrefsView, savedInstanceState);
+ setLoading(mIsLoading, false, true /* force */);
+ mPrefsView.addView(mPreferencesContainer);
+ return rootView;
+ }
+
+ protected void setLoading(boolean loading, boolean animate) {
+ setLoading(loading, animate, false);
+ }
+
+ private void setLoading(boolean loading, boolean animate, boolean force) {
+ if (mIsLoading != loading || force) {
+ mIsLoading = loading;
+ if (getView() == null) {
+ // If there is no created view, there is no reason to animate.
+ animate = false;
+ }
+ if (mPrefsView != null) {
+ setViewShown(mPrefsView, !loading, animate);
+ }
+ if (mLoadingView != null) {
+ setViewShown(mLoadingView, loading, animate);
+ }
+ }
+ }
+
+ @Override
+ public ListView getListView() {
+ ListView listView = super.getListView();
+ if (listView.getEmptyView() == null) {
+ TextView emptyView = (TextView) getView().findViewById(R.id.no_permissions);
+ listView.setEmptyView(emptyView);
+ }
+ return listView;
+ }
+
+ private void setViewShown(final View view, boolean shown, boolean animate) {
+ if (animate) {
+ Animation animation = AnimationUtils.loadAnimation(getContext(),
+ shown ? android.R.anim.fade_in : android.R.anim.fade_out);
+ if (shown) {
+ view.setVisibility(View.VISIBLE);
+ } else {
+ animation.setAnimationListener(new AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ view.setVisibility(View.INVISIBLE);
+ }
+ });
+ }
+ view.startAnimation(animation);
+ } else {
+ view.clearAnimation();
+ view.setVisibility(shown ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/SettingsWithHeader.java b/src/com/android/packageinstaller/permission/ui/handheld/SettingsWithHeader.java
index 7b58fed1..c15a4287 100644
--- a/src/com/android/packageinstaller/permission/ui/SettingsWithHeader.java
+++ b/src/com/android/packageinstaller/permission/ui/handheld/SettingsWithHeader.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.packageinstaller.permission.ui;
+package com.android.packageinstaller.permission.ui.handheld;
import android.content.Intent;
import android.graphics.drawable.Drawable;
@@ -26,6 +26,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.utils.Utils;
@@ -42,7 +43,7 @@ public abstract class SettingsWithHeader extends PermissionsFrameFragment
Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState);
- if (!Utils.isTelevision(getContext())) {
+ if (!DeviceUtils.isTelevision(getContext())) {
mHeader = inflater.inflate(R.layout.header, root, false);
getPreferencesContainer().addView(mHeader, 0);
updateHeader();
@@ -81,5 +82,4 @@ public abstract class SettingsWithHeader extends PermissionsFrameFragment
public void onClick(View v) {
getActivity().startActivity(mInfoIntent);
}
-
}
diff --git a/src/com/android/packageinstaller/permission/ui/AllAppPermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/television/AllAppPermissionsFragment.java
index 2fb9a510..d4910128 100644
--- a/src/com/android/packageinstaller/permission/ui/AllAppPermissionsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/television/AllAppPermissionsFragment.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.packageinstaller.permission.ui;
+package com.android.packageinstaller.permission.ui.television;
import android.app.ActionBar;
import android.app.AlertDialog;
diff --git a/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/television/AppPermissionsFragment.java
index 6396c61e..42a2661c 100644
--- a/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/television/AppPermissionsFragment.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.packageinstaller.permission.ui;
+package com.android.packageinstaller.permission.ui.television;
import android.annotation.Nullable;
import android.app.ActionBar;
@@ -50,6 +50,7 @@ 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.utils.LocationUtils;
import com.android.packageinstaller.permission.utils.SafetyNetLogger;
import com.android.packageinstaller.permission.utils.Utils;
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsTvViewHandler.java b/src/com/android/packageinstaller/permission/ui/television/GrantPermissionsViewHandlerImpl.java
index 0e979ab6..a2538821 100644
--- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsTvViewHandler.java
+++ b/src/com/android/packageinstaller/permission/ui/television/GrantPermissionsViewHandlerImpl.java
@@ -1,4 +1,4 @@
-package com.android.packageinstaller.permission.ui;
+package com.android.packageinstaller.permission.ui.television;
import android.content.Context;
import android.graphics.PixelFormat;
@@ -15,11 +15,12 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler;
/**
* TV-specific view handler for the grant permissions activity.
*/
-final class GrantPermissionsTvViewHandler implements GrantPermissionsViewHandler, OnClickListener {
+public final class GrantPermissionsViewHandlerImpl implements GrantPermissionsViewHandler, OnClickListener {
private static final String ARG_GROUP_NAME = "ARG_GROUP_NAME";
@@ -37,12 +38,12 @@ final class GrantPermissionsTvViewHandler implements GrantPermissionsViewHandler
private Button mSoftDenyButton;
private Button mHardDenyButton;
- GrantPermissionsTvViewHandler(Context context) {
+ public GrantPermissionsViewHandlerImpl(Context context) {
mContext = context;
}
@Override
- public GrantPermissionsTvViewHandler setResultListener(ResultListener listener) {
+ public GrantPermissionsViewHandlerImpl setResultListener(ResultListener listener) {
mResultListener = listener;
return this;
}
diff --git a/src/com/android/packageinstaller/permission/ui/ManagePermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/television/ManagePermissionsFragment.java
index e5e06e09..47301f48 100644
--- a/src/com/android/packageinstaller/permission/ui/ManagePermissionsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/television/ManagePermissionsFragment.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.packageinstaller.permission.ui;
+package com.android.packageinstaller.permission.ui.television;
import android.annotation.Nullable;
import android.app.ActionBar;
@@ -202,7 +202,7 @@ public final class ManagePermissionsFragment extends PermissionsFrameFragment
Preference extraScreenPreference = new Preference(context);
extraScreenPreference.setKey(EXTRA_PREFS_KEY);
extraScreenPreference.setIcon(Utils.applyTint(context,
- com.android.internal.R.drawable.ic_more_items,
+ R.drawable.ic_more_items,
android.R.attr.colorControlNormal));
extraScreenPreference.setTitle(R.string.additional_permissions);
extraScreenPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
diff --git a/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java b/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java
index 8dacd037..0f240bef 100644
--- a/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.packageinstaller.permission.ui;
+package com.android.packageinstaller.permission.ui.television;
import android.app.ActionBar;
import android.app.AlertDialog;
@@ -39,11 +39,13 @@ 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;
import com.android.packageinstaller.permission.model.PermissionApps.Callback;
import com.android.packageinstaller.permission.model.PermissionApps.PermissionApp;
+import com.android.packageinstaller.permission.ui.OverlayTouchActivity;
import com.android.packageinstaller.permission.utils.LocationUtils;
import com.android.packageinstaller.permission.utils.SafetyNetLogger;
import com.android.packageinstaller.permission.utils.Utils;
@@ -185,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/PermissionsFrameFragment.java b/src/com/android/packageinstaller/permission/ui/television/PermissionsFrameFragment.java
index 40058f6d..e81aee86 100644
--- a/src/com/android/packageinstaller/permission/ui/PermissionsFrameFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/television/PermissionsFrameFragment.java
@@ -1,4 +1,20 @@
-package com.android.packageinstaller.permission.ui;
+/*
+ * 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.television;
import android.annotation.Nullable;
import android.os.Bundle;
@@ -15,6 +31,7 @@ import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.TextView;
+import com.android.packageinstaller.DeviceUtils;
import com.android.packageinstaller.R;
import com.android.packageinstaller.permission.utils.Utils;
@@ -117,7 +134,7 @@ public abstract class PermissionsFrameFragment extends PreferenceFragment {
@Override
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
- if (Utils.isTelevision(getContext())) {
+ if (DeviceUtils.isTelevision(getContext())) {
mGridView = (VerticalGridView) inflater.inflate(
R.layout.leanback_preferences_list, parent, false);
mGridView.setWindowAlignmentOffset(0);
diff --git a/src/com/android/packageinstaller/permission/ui/television/SettingsWithHeader.java b/src/com/android/packageinstaller/permission/ui/television/SettingsWithHeader.java
new file mode 100644
index 00000000..4dae629c
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/television/SettingsWithHeader.java
@@ -0,0 +1,86 @@
+/*
+ * 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.television;
+
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+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.utils.Utils;
+
+public abstract class SettingsWithHeader extends PermissionsFrameFragment
+ implements OnClickListener {
+
+ private View mHeader;
+ protected Intent mInfoIntent;
+ protected Drawable mIcon;
+ protected CharSequence mLabel;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ ViewGroup root = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState);
+
+ if (!DeviceUtils.isTelevision(getContext())) {
+ mHeader = inflater.inflate(R.layout.header, root, false);
+ getPreferencesContainer().addView(mHeader, 0);
+ updateHeader();
+ }
+
+ return root;
+ }
+
+ public void setHeader(Drawable icon, CharSequence label, Intent infoIntent) {
+ mIcon = icon;
+ mLabel = label;
+ mInfoIntent = infoIntent;
+ updateHeader();
+ }
+
+ private void updateHeader() {
+ if (mHeader != null) {
+ final ImageView appIcon = (ImageView) mHeader.findViewById(R.id.icon);
+ appIcon.setImageDrawable(mIcon);
+
+ final TextView appName = (TextView) mHeader.findViewById(R.id.name);
+ appName.setText(mLabel);
+
+ final View info = mHeader.findViewById(R.id.info);
+ if (mInfoIntent == null) {
+ info.setVisibility(View.GONE);
+ } else {
+ info.setVisibility(View.VISIBLE);
+ info.setClickable(true);
+ info.setOnClickListener(this);
+ }
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ getActivity().startActivity(mInfoIntent);
+ }
+
+}
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/LocationUtils.java b/src/com/android/packageinstaller/permission/utils/LocationUtils.java
index 512fcf44..0296ae80 100644
--- a/src/com/android/packageinstaller/permission/utils/LocationUtils.java
+++ b/src/com/android/packageinstaller/permission/utils/LocationUtils.java
@@ -36,23 +36,9 @@ public class LocationUtils {
public static final String LOCATION_PERMISSION = Manifest.permission_group.LOCATION;
- public static ArrayList<String> getLocationProviders() {
- ArrayList<String> providers = new ArrayList<>();
- Resources res = Resources.getSystem();
- providers.add(res.getString(
- com.android.internal.R.string.config_networkLocationProviderPackageName));
-
- for (String provider :
- res.getStringArray(com.android.internal.R.array.config_locationProviderPackageNames)) {
- providers.add(provider);
- }
-
- return providers;
- }
-
public static void showLocationDialog(final Context context, CharSequence label) {
new AlertDialog.Builder(context)
- .setIcon(com.android.internal.R.drawable.ic_dialog_alert_material)
+ .setIcon(R.drawable.ic_dialog_alert_material)
.setTitle(android.R.string.dialog_alert_title)
.setMessage(context.getString(R.string.location_warning, label))
.setNegativeButton(R.string.ok, null)
@@ -83,5 +69,4 @@ public class LocationUtils {
return false;
}
}
-
}
diff --git a/src/com/android/packageinstaller/permission/utils/Utils.java b/src/com/android/packageinstaller/permission/utils/Utils.java
index 2940a729..21830378 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,20 @@ 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 info.isSystemApp() && (info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0
- && !launcherPkgs.contains(info.packageName);
+ return isSystem(app.getAppInfo(), launcherPkgs);
}
- 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 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);
}
}
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);
+ }
+}