summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-12-15 02:58:19 -0700
committerLinux Build Service Account <lnxbuild@localhost>2016-12-15 02:58:19 -0700
commitb687a3a2aa6b1a52ab919ca72f056389fbb2e4e8 (patch)
tree933f97c4bddd3e5408c35a28a24f990095fedefe
parent41dc63be55dbd9fc40ae666c0f8ae7117a0d6681 (diff)
parentd139f8ced98480b2d11ed0be792f291a17218ddd (diff)
downloadandroid_packages_apps_PackageInstaller-b687a3a2aa6b1a52ab919ca72f056389fbb2e4e8.zip
android_packages_apps_PackageInstaller-b687a3a2aa6b1a52ab919ca72f056389fbb2e4e8.tar.gz
android_packages_apps_PackageInstaller-b687a3a2aa6b1a52ab919ca72f056389fbb2e4e8.tar.bz2
Merge d139f8ced98480b2d11ed0be792f291a17218ddd on remote branch
Change-Id: Ib0c49c306aec1a4e6c5f1edbbb1065763a48fb3d
-rw-r--r--AndroidManifest.xml3
-rw-r--r--res/layout/grant_permissions.xml21
-rw-r--r--res/layout/header.xml2
-rw-r--r--res/layout/review_permissions.xml6
-rw-r--r--res/values-am/strings.xml2
-rw-r--r--res/values-bg/strings.xml2
-rw-r--r--res/values-bn-rBD/strings.xml2
-rw-r--r--res/values-es-rUS/strings.xml2
-rw-r--r--res/values-et-rEE/strings.xml2
-rw-r--r--res/values-eu-rES/strings.xml2
-rw-r--r--res/values-fa/strings.xml2
-rw-r--r--res/values-fi/strings.xml2
-rw-r--r--res/values-gl-rES/strings.xml2
-rw-r--r--res/values-gu-rIN/strings.xml2
-rw-r--r--res/values-hy-rAM/strings.xml4
-rw-r--r--res/values-ja/strings.xml4
-rw-r--r--res/values-ka-rGE/strings.xml2
-rw-r--r--res/values-kn-rIN/strings.xml2
-rw-r--r--res/values-ko/strings.xml2
-rw-r--r--res/values-lt/strings.xml2
-rw-r--r--res/values-lv/strings.xml2
-rw-r--r--res/values-ml-rIN/strings.xml2
-rw-r--r--res/values-my-rMM-television/strings.xml2
-rw-r--r--res/values-my-rMM/strings.xml36
-rw-r--r--res/values-pl/strings.xml2
-rw-r--r--res/values-pt-rBR/strings.xml2
-rw-r--r--res/values-pt-rPT/strings.xml2
-rw-r--r--res/values-pt/strings.xml2
-rw-r--r--res/values-ro/strings.xml2
-rw-r--r--res/values-ru/strings.xml4
-rw-r--r--res/values-si-rLK/strings.xml2
-rw-r--r--res/values-sk/strings.xml2
-rw-r--r--res/values-sv/strings.xml2
-rw-r--r--res/values-sw/strings.xml2
-rw-r--r--res/values-te-rIN/strings.xml2
-rw-r--r--res/values-tr/strings.xml2
-rw-r--r--res/values-uz-rUZ/strings.xml2
-rw-r--r--res/values-zh-rCN/strings.xml2
-rwxr-xr-xres/values/styles.xml2
-rwxr-xr-xsrc/com/android/packageinstaller/InstallAppProgress.java20
-rw-r--r--src/com/android/packageinstaller/PackageInstallerActivity.java82
-rw-r--r--[-rwxr-xr-x]src/com/android/packageinstaller/permission/model/AppPermissionGroup.java22
-rw-r--r--src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java36
-rw-r--r--src/com/android/packageinstaller/permission/ui/ManualLayoutFrame.java7
-rw-r--r--src/com/android/packageinstaller/permission/ui/OverlayTouchActivity.java2
-rw-r--r--src/com/android/packageinstaller/permission/ui/SecureButtonView.java56
-rwxr-xr-xsrc/com/android/packageinstaller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.java2
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java33
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java23
-rw-r--r--src/com/android/packageinstaller/wear/InstallTask.java173
-rw-r--r--src/com/android/packageinstaller/wear/InstallerConstants.java59
-rw-r--r--src/com/android/packageinstaller/wear/PackageInstallerFactory.java36
-rw-r--r--src/com/android/packageinstaller/wear/PackageInstallerImpl.java324
-rw-r--r--src/com/android/packageinstaller/wear/WearPackageArgs.java6
-rw-r--r--src/com/android/packageinstaller/wear/WearPackageInstallerService.java82
55 files changed, 898 insertions, 207 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 39e9f3c..83364bd 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -22,9 +22,6 @@
<uses-permission android:name="com.google.android.permission.INSTALL_WEARABLE_PACKAGES" />
- <!-- Needed for passing extras with intent ACTION_SHOW_ADMIN_SUPPORT_DETAILS -->
- <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
-
<application android:label="@string/app_name"
android:allowBackup="false"
android:theme="@style/Theme.DialogWhenLarge"
diff --git a/res/layout/grant_permissions.xml b/res/layout/grant_permissions.xml
index 92c0df9..8ed9c5d 100644
--- a/res/layout/grant_permissions.xml
+++ b/res/layout/grant_permissions.xml
@@ -19,18 +19,21 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clipChildren="false"
- android:paddingLeft="@*android:dimen/floating_window_margin_left"
- android:paddingRight="@*android:dimen/floating_window_margin_right"
- android:paddingTop="@*android:dimen/floating_window_margin_top"
- android:paddingBottom="@*android:dimen/floating_window_margin_bottom"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="32dp"
android:clipToPadding="false">
+ <ScrollView android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
<LinearLayout
android:id="@+id/dialog_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:elevation="@*android:dimen/floating_window_z"
+ android:elevation="16dp"
android:background="@drawable/dialog_background">
<FrameLayout
@@ -87,7 +90,7 @@
</TextView>
<Space
- android:id="@*android:id/spacer"
+ android:id="@+id/spacer"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
@@ -102,13 +105,13 @@
android:text="@string/grant_dialog_button_deny" >
</Button>
- <com.android.packageinstaller.permission.ui.SecureButtonView
+ <Button
android:id="@+id/permission_allow_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="?android:attr/buttonBarButtonStyle"
android:text="@string/grant_dialog_button_allow" >
- </com.android.packageinstaller.permission.ui.SecureButtonView>
+ </Button>
</com.android.packageinstaller.permission.ui.ButtonBarLayout>
@@ -116,4 +119,6 @@
</LinearLayout>
+ </ScrollView>
+
</com.android.packageinstaller.permission.ui.ManualLayoutFrame>
diff --git a/res/layout/header.xml b/res/layout/header.xml
index fa6515b..a444945 100644
--- a/res/layout/header.xml
+++ b/res/layout/header.xml
@@ -17,7 +17,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
- android:background="?android:attr/colorPrimary"
+ android:background="?android:attr/colorSecondary"
android:gravity="center_vertical" >
<ImageView android:id="@+id/icon"
diff --git a/res/layout/review_permissions.xml b/res/layout/review_permissions.xml
index 462f9a5..71d3191 100644
--- a/res/layout/review_permissions.xml
+++ b/res/layout/review_permissions.xml
@@ -56,7 +56,7 @@
android:layout_weight="1">
</FrameLayout>
- <com.android.internal.widget.ButtonBarLayout
+ <com.android.packageinstaller.permission.ui.ButtonBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
@@ -64,7 +64,7 @@
android:paddingTop="16dip">
<Space
- android:id="@*android:id/spacer"
+ android:id="@+id/spacer"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
@@ -85,6 +85,6 @@
android:layout_marginStart="8dip"
android:text="@string/review_button_continue" />
- </com.android.internal.widget.ButtonBarLayout>
+ </com.android.packageinstaller.permission.ui.ButtonBarLayout>
</LinearLayout>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index e3bca1f..8cb9dac 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"ከልክል"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"ለማንኛውም ከልክል"</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="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g> እንዲያደርግ ይፈቀድለት?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g> እንዲከናወን ይፈቀድለት?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"ፍቀድ"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"መተግበሪያዎች"</string>
<string name="app_permissions" msgid="3146758905824597178">"የመተግበሪያ ፈቃዶች"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index b4617d1..20cc187 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Отказване"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Отказване въпреки това"</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="7332275268559121742">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; следното действие: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"Разрешаване на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Разрешаване"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Приложения"</string>
<string name="app_permissions" msgid="3146758905824597178">"Разрешения за приложения"</string>
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml
index 4769297..f068b08 100644
--- a/res/values-bn-rBD/strings.xml
+++ b/res/values-bn-rBD/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"প্রত্যাখ্যান করুন"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"যাইহোক অস্বীকার করুন"</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>
- <string name="permission_warning_template" msgid="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;কে <xliff:g id="ACTION">%2$s</xliff:g> এ অনুমতি দেবেন?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;কে <xliff:g id="ACTION">%2$s</xliff:g> এর অনুমতি দেবেন?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"অনুমতি দিন"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"অ্যাপ্লিকেশানগুলি"</string>
<string name="app_permissions" msgid="3146758905824597178">"অ্যাপ্লিকেশানের অনুমতি"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 14e7ab3..894f1c7 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Rechazar"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Denegar de todos modos"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> de <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="7332275268559121742">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; realice la siguiente acción: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"¿Permitir que la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; realice la siguiente acción: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Permitir"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Aplicaciones"</string>
<string name="app_permissions" msgid="3146758905824597178">"Permisos de aplicaciones"</string>
diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml
index 8460979..9bb9860 100644
--- a/res/values-et-rEE/strings.xml
+++ b/res/values-et-rEE/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Keela"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Keela ikkagi"</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>-st"</string>
- <string name="permission_warning_template" msgid="7332275268559121742">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toiming <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Luba"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Rakendused"</string>
<string name="app_permissions" msgid="3146758905824597178">"Rakenduse load"</string>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
index e6bb23b..f4a14e7 100644
--- a/res/values-eu-rES/strings.xml
+++ b/res/values-eu-rES/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Ukatu"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Ukatu hala ere"</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="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioak <xliff:g id="ACTION">%2$s</xliff:g> ahal izatea baimendu nahi duzu?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari <xliff:g id="ACTION">%2$s</xliff:g> baimena eman nahi diozu?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Baimendu"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Aplikazioak"</string>
<string name="app_permissions" msgid="3146758905824597178">"Aplikaziorako baimenak"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index b6832f6..023f116 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -98,7 +98,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> مورد دیگر</item>
</plurals>
<string name="old_sdk_deny_warning" msgid="3872277112584842615">"‏این برنامه برای یک نسخه قدیمی‌تر از Android طراحی شده بود. نپذیرفتن اجازه ممکن است باعث شود که برنامه دیگر به صورتی که مورد نظر است کار نکند."</string>
- <string name="default_permission_description" msgid="4992892207044156668">"انجام یک اقدام ناشناخته"</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>
<string name="menu_hide_system" msgid="7595471742649432977">"پنهان کردن سیستم"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 2ab0e82..c1fff93 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Estä"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Kiellä silti"</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="7332275268559121742">"Sallitaanko toiminto <xliff:g id="ACTION">%2$s</xliff:g> sovellukselle &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Salli"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Sovellukset"</string>
<string name="app_permissions" msgid="3146758905824597178">"Sovelluksen käyttöoikeudet"</string>
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml
index dbc8d4a..478d688 100644
--- a/res/values-gl-rES/strings.xml
+++ b/res/values-gl-rES/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Denegar"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Denegar igualmente"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> de <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="7332275268559121742">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"Queres permitir á aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Permitir"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Aplicacións"</string>
<string name="app_permissions" msgid="3146758905824597178">"Permisos de aplicacións"</string>
diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu-rIN/strings.xml
index 4dcef19..d5ac034 100644
--- a/res/values-gu-rIN/strings.xml
+++ b/res/values-gu-rIN/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"નકારો"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"કોઇપણ રીતે નકારો"</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>
- <string name="permission_warning_template" msgid="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ને <xliff:g id="ACTION">%2$s</xliff:g> માટેની મંજૂરી આપીએ?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ને <xliff:g id="ACTION">%2$s</xliff:g> મંજૂરી આપીએ?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"મંજૂરી આપો"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"ઍપ્લિકેશનો"</string>
<string name="app_permissions" msgid="3146758905824597178">"ઍપ્લિકેશન પરવાનગીઓ"</string>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
index 33ac99e..b7d5c2a 100644
--- a/res/values-hy-rAM/strings.xml
+++ b/res/values-hy-rAM/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Մերժել"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Մերժել ամեն դեպքում"</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="7332275268559121742">"Թույլ տա՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին կատարել հետևյալ գործողությունը՝ <xliff:g id="ACTION">%2$s</xliff:g>:"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"Թո՞ւյլ տալ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին <xliff:g id="ACTION">%2$s</xliff:g>:"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Թույլատրել"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Հավելվածներ"</string>
<string name="app_permissions" msgid="3146758905824597178">"Հավելվածների թույլտվությունները"</string>
@@ -112,7 +112,7 @@
<string name="all_permissions" msgid="5156669007784613042">"Բոլոր թույլտվությունները"</string>
<string name="other_permissions" msgid="2016192512386091933">"Այլ հավելվածների հնարավորությունները"</string>
<string name="permission_request_title" msgid="1204446718549121199">"Թույլտվության հարցում"</string>
- <string name="screen_overlay_title" msgid="3021729846864038529">"Հայտնաբերվել է էկրանի վերադրում"</string>
+ <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>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 94a943a..dede308 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"許可しない"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"許可しない"</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="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に「<xliff:g id="ACTION">%2$s</xliff:g>」を許可しますか?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に<xliff:g id="ACTION">%2$s</xliff:g>を許可しますか?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"許可"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"アプリ"</string>
<string name="app_permissions" msgid="3146758905824597178">"アプリの権限"</string>
@@ -117,7 +117,7 @@
<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="1322352525843583064">"Wear ではインストールやアンインストールができません"</string>
- <string name="permission_review_warning_title_template_update" msgid="2569412700408535872">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」が更新されました。「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」に次の権限を許可しますか?"</string>
+ <string name="permission_review_warning_title_template_update" msgid="2569412700408535872">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> が更新されました。<xliff:g id="APP_NAME_1">%1$s</xliff:g> に次の権限を許可しますか?"</string>
<string name="permission_review_title_template_install" msgid="6535540493936469336">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」に許可する権限の選択"</string>
<string name="permission_review_title_template_update" msgid="2548815248828051885">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」が更新されました。このアプリに許可する権限を選択してください。"</string>
<string name="review_button_cancel" msgid="957906817733578877">"キャンセル"</string>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
index d8f9f0a..a061077 100644
--- a/res/values-ka-rGE/strings.xml
+++ b/res/values-ka-rGE/strings.xml
@@ -87,7 +87,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"უარყოფა"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"მაინც უარყოფა"</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="7332275268559121742">"გსურთ, დაუშვათ, რომ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-მა შეასრულოს <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"გსურთ, დაუშვათ, რომ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;მ შეასრულოს <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"დაშვება"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"აპები"</string>
<string name="app_permissions" msgid="3146758905824597178">"აპის უფლებები"</string>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
index 60b7948..4a64b97 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn-rIN/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"ನಿರಾಕರಿಸು"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"ಹೇಗಾದರೂ ನಿರಾಕರಿಸಿ"</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>
- <string name="permission_warning_template" msgid="7332275268559121742">"<xliff:g id="ACTION">%2$s</xliff:g> ಗೆ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"<xliff:g id="ACTION">%2$s</xliff:g> <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"ಅನುಮತಿಸು"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
<string name="app_permissions" msgid="3146758905824597178">"ಅಪ್ಲಿಕೇಶನ್ ಅನುಮತಿಗಳು"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 54c32f7..4e68fa2 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"거부"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"거부"</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="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;이(가) <xliff:g id="ACTION">%2$s</xliff:g>을(를) 할 수 있도록 허용하시겠습니까?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;의 다음 작업을 허용하시겠습니까? <xliff:g id="ACTION">%2$s</xliff:g>"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"허용"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"앱"</string>
<string name="app_permissions" msgid="3146758905824597178">"앱 권한"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 0ec3979..2b7ee68 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Atmesti"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Vis tiek atmesti"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> iš <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="7332275268559121742">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"Leisti programai &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Leisti"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Programos"</string>
<string name="app_permissions" msgid="3146758905824597178">"Programos leidimai"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index bcd517a..15da1a0 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Neatļaut"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Tomēr noraidīt"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>. no <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="7332275268559121742">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; veikt šādu darbību: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Atļaut"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Lietotnes"</string>
<string name="app_permissions" msgid="3146758905824597178">"Lietotnes atļaujas"</string>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
index 74e4e92..32de106 100644
--- a/res/values-ml-rIN/strings.xml
+++ b/res/values-ml-rIN/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"നിരസിക്കുക"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"എന്തായാലും നിരസിക്കുക"</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="7332275268559121742">"<xliff:g id="ACTION">%2$s</xliff:g> ചെയ്യുന്നതിന് &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്ന ആപ്പിനെ അനുവദിക്കണോ?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"<xliff:g id="ACTION">%2$s</xliff:g> &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"അനുവദിക്കുക"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"ആപ്സ്"</string>
<string name="app_permissions" msgid="3146758905824597178">"ആപ്പ് അനുമതികൾ"</string>
diff --git a/res/values-my-rMM-television/strings.xml b/res/values-my-rMM-television/strings.xml
index 17e82c3..b802f59 100644
--- a/res/values-my-rMM-television/strings.xml
+++ b/res/values-my-rMM-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">"ငြင်းဆိုပြီး ထပ်မံ မမေးပါနှင့်"</string>
- <string name="grant_dialog_how_to_change" msgid="615414835189256888">"နောင်တွင် ဤသည်အား ဆက်တင်များ &gt; App များတွင် ပြင်နိုင်၏"</string>
+ <string name="grant_dialog_how_to_change" msgid="615414835189256888">"နောင်တွင် ဤသည်အား ဆက်တင်များ &gt; အက်ပ်များတွင် ပြင်နိုင်၏"</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">"စနစ်အပ်ဖ်များ ပြသရန်"</string>
<string name="app_permissions_decor_title" msgid="1461057434211920209">"အက်ပ်ခွင့်ပြုချက်များ"</string>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
index ae53bf8..2022199 100644
--- a/res/values-my-rMM/strings.xml
+++ b/res/values-my-rMM/strings.xml
@@ -21,21 +21,21 @@
<string name="install" msgid="5896438203900042068">"ထည့်သွင်းပါ"</string>
<string name="done" msgid="3889387558374211719">"ပြီးပါပြီ"</string>
<string name="security_settings_desc" msgid="2706691034244052604">"ဒီအပလီကေးရှင်းကို ခွင့်ပြုရမှာကတော့:"</string>
- <string name="cancel" msgid="8360346460165114585">"မလုပ်တော့ပါ"</string>
+ <string name="cancel" msgid="8360346460165114585">"မလုပ်တော့"</string>
<string name="unknown" msgid="4742479012767208045">"အကြောင်းအရာ မသိရှိ"</string>
<string name="installing" msgid="8613631001631998372">"ထည့်သွင်းနေပါသည်"</string>
- <string name="install_done" msgid="3682715442154357097">"အက်ပ် ထည့်သွင်းပြီး"</string>
+ <string name="install_done" msgid="3682715442154357097">"အက်ပ်ထည့်သွင်းပြီး"</string>
<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_no_perms" msgid="4885928136844618944">"လက်ရှိ ရှိပြီးသား အပလီကေးရှင်းကို အဆင့်မြှင့်လိုပါသလား။ ရှိပြီးသား အချက်အလက်များကို ဆုံးရှုံးမည် မဟုတ်ပါ။ အထူးတလည် သုံးခွင့် မလိုအပ်ပါ"</string>
- <string name="install_confirm_question_update_system_no_perms" msgid="7676593512694724374">"အဆင့်သင့် ပါလာသော အပလီကေးရှင်းကို အဆင့်မြှင့်လိုပါသလား။ ရှိပြီးသား အချက်အလက်များကို ဆုံးရှုံးမည် မဟုတ်ပါ။ အထူးတလည် သုံးခွင့် မလိုအပ်ပါ"</string>
- <string name="install_failed" msgid="6579998651498970899">"အက်ပ် မထည့်သွင်းရသေးပါ"</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_no_perms" msgid="4885928136844618944">"လက်ရှိ ရှိပြီးသား အပလီကေးရှင်းကို အပ်ဒိတ်လုပ်လိုပါသလား။ ရှိပြီးသား အချက်အလက်များကို ဆုံးရှုံးမည် မဟုတ်ပါ။ အထူးတလည် သုံးခွင့် မလိုအပ်ပါ"</string>
+ <string name="install_confirm_question_update_system_no_perms" msgid="7676593512694724374">"အဆင့်သင့် ပါလာသော အပလီကေးရှင်းကို အပ်ဒိတ်လုပ်လိုပါသလား။ ရှိပြီးသား အချက်အလက်များကို ဆုံးရှုံးမည် မဟုတ်ပါ။ အထူးတလည် သုံးခွင့် မလိုအပ်ပါ"</string>
+ <string name="install_failed" msgid="6579998651498970899">"အက်ပ်မထည့်သွင်းရသေးပါ"</string>
<string name="install_failed_blocked" msgid="1606870930588770025">"ပက်ကေ့ထည့်သွင်းခြင်းကို ပိတ်ဆို့ထားသည်။"</string>
<string name="install_failed_conflict" msgid="5349055145440204106">"ပက်ကေ့သည် အမည်တူနေသည့် တည်ရှိနေပြီးသားပက်ကေ့ဖြင့် တိုက်နေသည်။"</string>
<string name="install_failed_incompatible" product="tablet" msgid="119054044615117271">"ဤအပလီကေးရှင်းက သင့်တက်ဘလက်နဲ့ မသင့်တော်ပါ"</string>
- <string name="install_failed_incompatible" product="tv" msgid="3553367270510072729">"ဤ အက်ပ် သည် သင့်တီဗွီနှင့် တွဲဖက်သုံးမရပါ။"</string>
+ <string name="install_failed_incompatible" product="tv" msgid="3553367270510072729">"ဤ အက်ပ်သည် သင့်တီဗွီနှင့် တွဲဖက်သုံးမရပါ။"</string>
<string name="install_failed_incompatible" product="default" msgid="6677057915876853610">"ဤအပလီကေးရှင်းက သင့်ဖုန်းနဲ့ မသင့်တော်ပါ"</string>
<string name="install_failed_invalid_apk" msgid="1287935707565682604">"ဤpackageမှာ ဖျက်စီးသွားပါသည်။"</string>
<string name="install_failed_msg" product="tablet" msgid="8368835262605608787">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကို သင့်တက်ဘလက်တွင် ထည့်သွင်းလို့ မရနိုင်ပါ"</string>
@@ -51,14 +51,14 @@
<string name="manage_applications" msgid="4033876279091996596">"အပလီကေးရှင်းများအား ထိန်းသိမ်းခြင်း"</string>
<string name="dlg_app_replacement_title" msgid="1232230739563820951">"အပလီကေးရှင်းအား အစားထိုးမညိလား?"</string>
<string name="dlg_app_replacement_statement" msgid="2992911899989907492">"သင် ထည့်သွင်းနေသော အပလီကေးရှင်းမှာ တခြား အပလီကေးရှင်းတစ်ခုအား အစားထိုးပါမည်။.\n\n ယခင်သိမ်းဆည်းထားသော အချက်အလက်များ ကို သိမ်းဆည်းပေးပါမည်။"</string>
- <string name="dlg_sys_app_replacement_statement" msgid="1900046590819605929">"ဒီဟာသည် စနစ်၏အက်ပ် ဖြစ်ပါသည်။ \n\nယခင် သုံးစွဲသူအချက်အလက်များ ကို သိမ်းဆည်းပေးပါမည်။"</string>
+ <string name="dlg_sys_app_replacement_statement" msgid="1900046590819605929">"ဒီဟာသည် စနစ်၏အက်ပ်ဖြစ်ပါသည်။ \n\nယခင် သုံးစွဲသူအချက်အလက်များ ကို သိမ်းဆည်းပေးပါမည်။"</string>
<string name="out_of_space_dlg_title" msgid="7843674437613797326">"နေရာလွတ်မရှိပါ"</string>
<string name="out_of_space_dlg_text" msgid="4774775404294282216">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကို ထည့်သွင်းလို့ မရနိုင်ပါ။ နေရာအပိုရအောင် ရှင်းလင်းပြီး ပြန်ကြိုးစားပါ"</string>
<string name="dlg_ok" msgid="6944357727705699232">"အိုကေ"</string>
- <string name="app_not_found_dlg_title" msgid="2692335460569505484">"အက်ပ် အားမတွေ့ပါ"</string>
+ <string name="app_not_found_dlg_title" msgid="2692335460569505484">"အက်ပ်အားမတွေ့ပါ"</string>
<string name="app_not_found_dlg_text" msgid="6107465056055095930">"ထည့်သွင်းထားသော အပလီကေးရှင်းထဲတွင် ဤအပလီကေးရှင်း မတွေ့ရှိပါ"</string>
<string name="uninstall_application_title" msgid="1860074100811653963">"အပလီကေးရှင်းကို ဖယ်ရှားပါ"</string>
- <string name="uninstall_update_title" msgid="4146940097553335390">"အဆင့်မြှင့်ခြင်းကို ဖယ်ရှားပါ"</string>
+ <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>
@@ -81,15 +81,15 @@
<string name="allPerms" msgid="1024385515840703981">"အားလုံး"</string>
<string name="privacyPerms" msgid="1850527049572617">"လုံခြုံမှု"</string>
<string name="devicePerms" msgid="6733560207731294504">"စက်ပစ္စည်း အသုံးပြုခွင့်"</string>
- <string name="no_new_perms" msgid="6657813692169565975">"ဒီအဆင့်မြှင့်ခြင်းဟာ ခွင့်ပြုချက်သစ်တွေ မလိုအပ်ပါ"</string>
+ <string name="no_new_perms" msgid="6657813692169565975">"ဤအပ်ဒိတ်အတွက် ခွင့်ပြုချက်အသစ် မလိုအပ်ပါ"</string>
<string name="grant_confirm_question" msgid="4690289297029223742">"အောက်ပါ ခွင့်ပြုချက်များ ပေးလိုပါသလား။ ၎င်းတို့က သုံးခွင့်ပြုမှာကတော့၊"</string>
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"ငြင်းပယ်သည်"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"မည်သို့ပင်ဖြစ်စေ ငြင်းပယ်ပါ"</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="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ကို <xliff:g id="ACTION">%2$s</xliff:g> ရန်ခွင့်ပြုမလား။"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"ခွင့်ပြုသည်"</string>
- <string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Appများ"</string>
- <string name="app_permissions" msgid="3146758905824597178">"App ခွင့်ပြုချက်များ"</string>
+ <string name="app_permissions_breadcrumb" msgid="3390836200791539264">"အက်ပ်များ"</string>
+ <string name="app_permissions" msgid="3146758905824597178">"အက်ပ်ခွင့်ပြုချက်များ"</string>
<string name="never_ask_again" msgid="1089938738199748687">"နောက်ထပ်မမေးပါနှင့်"</string>
<string name="no_permissions" msgid="3210542466245591574">"ခွင့်ပြုချက်မရှိ"</string>
<string name="additional_permissions" msgid="6667573114240111763">"ထပ်တိုး ခွင့်ပြုချက်များ"</string>
@@ -99,7 +99,7 @@
</plurals>
<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="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>
<string name="menu_hide_system" msgid="7595471742649432977">"စနစ်ကို ဖျောက်မည်"</string>
<string name="permission_title" msgid="6495415273398916381">"<xliff:g id="PERMISSION">%1$s</xliff:g> ခွင့်ပြုချက်များ"</string>
@@ -113,15 +113,15 @@
<string name="other_permissions" msgid="2016192512386091933">"အခြားအပ်ဖ်၏ စွမ်းရည်များ"</string>
<string name="permission_request_title" msgid="1204446718549121199">"ခွင့်ပြုချက် တောင်းခံမှု"</string>
<string name="screen_overlay_title" msgid="3021729846864038529">"မျက်နှာပြင် ထပ်ပေးမှုကို ရှာတွေ့ခဲ့"</string>
- <string name="screen_overlay_message" msgid="2141944461571677331">"ဒီခွင့်ပြုချက် ဆက်တင်ကို ပြောင်းရန်၊ သင်ဟာ ဦးစွာ ဆက်တင်များ &gt; Appများ ထဲတွင် မျက်နှာပြင် ထပ်ပေးမှုကို ပိတ်လိုက်ရန် လိုမယ်"</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="1322352525843583064">"Wear ပေါ်တွင် ထည့်သွင်းခြင်း/ဖြုတ်ခြင်းများကို ပံ့ပိုးမထားပါ။"</string>
<string name="permission_review_warning_title_template_update" msgid="2569412700408535872">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ကို အပ်ဒိတ် လုပ်ခဲ့သည်။<xliff:g id="APP_NAME_1">%1$s</xliff:g> အား အောက်ဖေါ်ပြပါကို သုံးခွင့် ပြုရမလား။"</string>
<string name="permission_review_title_template_install" msgid="6535540493936469336">"<xliff:g id="APP_NAME">%1$s</xliff:g> အား သုံးခွင့် ပြုမှာကို ရွေးချယ်ပါ"</string>
<string name="permission_review_title_template_update" msgid="2548815248828051885">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကို အပ်ဒိတ် လုပ်ခဲ့သည်။ ဤအက်ပ်အား သုံးခွင့် ပြုမှာကို ရွေးချယ်ပါ။"</string>
- <string name="review_button_cancel" msgid="957906817733578877">"မလုပ်တော့ပါ"</string>
- <string name="review_button_continue" msgid="4809162078179371370">"ဆက်လုပ်ပါ"</string>
+ <string name="review_button_cancel" msgid="957906817733578877">"မလုပ်တော့"</string>
+ <string name="review_button_continue" msgid="4809162078179371370">"ဆက်လုပ်ရန်"</string>
<string name="new_permissions_category" msgid="3213523410139204183">"ခွင့်ပြုချက် အသစ်များ"</string>
<string name="current_permissions_category" msgid="998210994450606094">"လက်ရှိ ခွင့်ပြုချက်များ"</string>
<string name="message_staging" msgid="6151794817691100003">"အက်ပ်ကို ပြင်ဆင်နေသည်…"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 9f4a34e..cc7affc 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Odmów"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Odmów mimo to"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> z <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="7332275268559121742">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Zezwól"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Aplikacje"</string>
<string name="app_permissions" msgid="3146758905824597178">"Uprawnienia aplikacji"</string>
diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml
index d058b26..63c3835 100644
--- a/res/values-pt-rBR/strings.xml
+++ b/res/values-pt-rBR/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Negar"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Negar mesmo assim"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> de <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="7332275268559121742">"Permitir que o &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Permitir"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Apps"</string>
<string name="app_permissions" msgid="3146758905824597178">"Permissões do app"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index c6e1f96..279c79b 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Recusar"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Recusar mesmo assim"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> de <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="7332275268559121742">"Pretende permitir a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"Pretende permitir à(ao) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Permitir"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Aplicações"</string>
<string name="app_permissions" msgid="3146758905824597178">"Permissões da aplicação"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index d058b26..63c3835 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Negar"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Negar mesmo assim"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> de <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="7332275268559121742">"Permitir que o &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Permitir"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Apps"</string>
<string name="app_permissions" msgid="3146758905824597178">"Permissões do app"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 1006519..95017dd 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -100,7 +100,7 @@
</plurals>
<string name="old_sdk_deny_warning" msgid="3872277112584842615">"Această aplicație a fost creată pentru o versiune Android mai veche. Dacă nu acordați permisiunea, este posibil ca aceasta să nu mai funcționeze corespunzător."</string>
<string name="default_permission_description" msgid="4992892207044156668">"efectuează o acțiune necunoscută"</string>
- <string name="app_permissions_group_summary" msgid="4787239772223699263">"<xliff:g id="COUNT_0">%1$d</xliff:g> din <xliff:g id="COUNT_1">%2$d</xliff:g> (de) aplicații au această permisiune"</string>
+ <string name="app_permissions_group_summary" msgid="4787239772223699263">"<xliff:g id="COUNT_0">%1$d</xliff:g> din <xliff:g id="COUNT_1">%2$d</xliff:g> aplicații au această permisiune"</string>
<string name="menu_show_system" msgid="6773743421743728921">"Afișați aplicațiile de sistem"</string>
<string name="menu_hide_system" msgid="7595471742649432977">"Ascundeți aplicațiile de sistem"</string>
<string name="permission_title" msgid="6495415273398916381">"Permisiuni pentru <xliff:g id="PERMISSION">%1$s</xliff:g>"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index babad03..ff1556e 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -114,8 +114,8 @@
<string name="all_permissions" msgid="5156669007784613042">"Все разрешения"</string>
<string name="other_permissions" msgid="2016192512386091933">"Что ещё может приложение"</string>
<string name="permission_request_title" msgid="1204446718549121199">"Запрос разрешений"</string>
- <string name="screen_overlay_title" msgid="3021729846864038529">"Обнаружены наложения"</string>
- <string name="screen_overlay_message" msgid="2141944461571677331">"Чтобы предоставить или отменить разрешение, сначала отключите наложения. Для этого нажмите \"Настройки &gt; Приложения\"."</string>
+ <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="1322352525843583064">"Установка и удаление не поддерживаются на Android Wear"</string>
diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml
index 7f5b068..be7d78f 100644
--- a/res/values-si-rLK/strings.xml
+++ b/res/values-si-rLK/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"ප්‍රතික්ෂේප කරන්න"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"කෙසේ වෙතත් ප්‍රතික්ෂේප කරන්න"</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>
- <string name="permission_warning_template" msgid="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට <xliff:g id="ACTION">%2$s</xliff:g> වෙත ඉඩ දෙන්නද?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ට <xliff:g id="ACTION">%2$s</xliff:g> වෙත ඉඩ දෙන්නද?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"ඉඩ දෙන්න"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"යෙදුම්"</string>
<string name="app_permissions" msgid="3146758905824597178">"යෙදුම් අවසර"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index c6f6123..3cdd5d0 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Odmietnuť"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Zamietnuť"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> z <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="7332275268559121742">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; vykonať akciu <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Povoliť"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Aplikácie"</string>
<string name="app_permissions" msgid="3146758905824597178">"Povolenia aplikácií"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index ce8d0ac..a5dec78 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Neka"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Neka ändå"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> av <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="7332275268559121742">"Tillåter du &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; att göra följande: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"Tillåter du &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; att <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Tillåt"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Appar"</string>
<string name="app_permissions" msgid="3146758905824597178">"Appens behörigheter"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 1c0afe2..8e8630d 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Kataa"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Kataa"</string>
<string name="current_permission_template" msgid="6378304249516652817">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> kati ya <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="7332275268559121742">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; iweze <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"Ruhusu"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Programu"</string>
<string name="app_permissions" msgid="3146758905824597178">"Ruhusa za programu"</string>
diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml
index ef0c9f0..a0882dc 100644
--- a/res/values-te-rIN/strings.xml
+++ b/res/values-te-rIN/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"తిరస్కరించు"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"ఏదేమైనా నిరాకరించు"</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>
- <string name="permission_warning_template" msgid="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని <xliff:g id="ACTION">%2$s</xliff:g> చేయడానికి అనుమతించాలా?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని <xliff:g id="ACTION">%2$s</xliff:g> అనుమతించాలా?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"అనుమతించు"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"అనువర్తనాలు"</string>
<string name="app_permissions" msgid="3146758905824597178">"అనువర్తన అనుమతులు"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index c7d64fd..382d601 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -86,7 +86,7 @@
<string name="grant_dialog_button_deny" msgid="2176510645406614340">"Reddet"</string>
<string name="grant_dialog_button_deny_anyway" msgid="847960499284125250">"Yine de reddet"</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="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasına <xliff:g id="ACTION">%2$s</xliff:g> için izin verilsin mi?"</string>
+ <string name="permission_warning_template" msgid="7332275268559121742">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasına <xliff:g id="ACTION">%2$s</xliff:g> izni verilsin mi?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"İzin ver"</string>
<string name="app_permissions_breadcrumb" msgid="3390836200791539264">"Uygulamalar"</string>
<string name="app_permissions" msgid="3146758905824597178">"Uygulama izinleri"</string>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
index fb7d5e8..081a3d3 100644
--- a/res/values-uz-rUZ/strings.xml
+++ b/res/values-uz-rUZ/strings.xml
@@ -60,7 +60,7 @@
<string name="uninstall_application_title" msgid="1860074100811653963">"Ilovani o‘chirish"</string>
<string name="uninstall_update_title" msgid="4146940097553335390">"Yangilanishni o‘chirish"</string>
<string name="uninstall_activity_text" msgid="6680688689803932550">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> quyidagi ilovaning bir qismidir:"</string>
- <string name="uninstall_application_text" msgid="6691975835951187030">"Ushbu ilova o‘chirilsinmi?"</string>
+ <string name="uninstall_application_text" msgid="6691975835951187030">"Bu ilova o‘chirib tashlansinmi?"</string>
<string name="uninstall_application_text_all_users" msgid="5574704453233525222">"Ushbu ilova "<b>"barcha"</b>" foydalanuvchilar uchun o‘chirilsinmi? Ilova va uning ma’lumotlari qurilmadagi "<b>"barcha"</b>" foydalanuvchilardan o‘chib ketadi."</string>
<string name="uninstall_application_text_user" msgid="8766882355635485733">"Haqiqatdan ham <xliff:g id="USERNAME">%1$s</xliff:g> foydalanuvchi uchun ushbu ilovani olib tashlamoqchimisiz?"</string>
<string name="uninstall_update_text" msgid="1394549691152728409">"Bu ilova boshlang‘ich versiyasi bilan almashtirilsinmi? Barcha ma’lumotlar o‘chirib tashlanadi."</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 5ec5f6c..82b8569 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -89,7 +89,7 @@
<string name="permission_warning_template" msgid="7332275268559121742">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;<xliff:g id="ACTION">%2$s</xliff:g>吗?"</string>
<string name="grant_dialog_button_allow" msgid="4616529495342337095">"允许"</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="1089938738199748687">"不再询问"</string>
<string name="no_permissions" msgid="3210542466245591574">"没有权限"</string>
<string name="additional_permissions" msgid="6667573114240111763">"其他权限"</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index c69558b..fba0158 100755
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -17,7 +17,7 @@
<resources>
<style name="Theme.DialogWhenLarge"
- parent="@android:style/Theme.Material.Light.DialogWhenLarge.NoActionBar">
+ parent="@android:style/Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar">
<item name="android:textAppearanceMedium">@style/MediumText</item>
<item name="android:textAppearanceSmall">@style/SmallText</item>
<item name="android:titleTextStyle">@style/TitleText</item>
diff --git a/src/com/android/packageinstaller/InstallAppProgress.java b/src/com/android/packageinstaller/InstallAppProgress.java
index 7554704..49d91cf 100755
--- a/src/com/android/packageinstaller/InstallAppProgress.java
+++ b/src/com/android/packageinstaller/InstallAppProgress.java
@@ -34,6 +34,8 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageLite;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
@@ -48,6 +50,8 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.packageinstaller.permission.utils.IoUtils;
+import com.android.internal.content.PackageHelper;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -353,6 +357,22 @@ public class InstallAppProgress extends Activity implements View.OnClickListener
params.originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
UID_UNKNOWN);
+ File file = new File(mPackageURI.getPath());
+ try {
+ PackageLite pkg = PackageParser.parsePackageLite(file, 0);
+ params.setAppPackageName(pkg.packageName);
+ params.setInstallLocation(pkg.installLocation);
+ params.setSize(
+ PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
+ } catch (PackageParser.PackageParserException e) {
+ Log.e(TAG, "Cannot parse package " + file + ". Assuming defaults.");
+ Log.e(TAG, "Cannot calculate installed size " + file + ". Try only apk size.");
+ params.setSize(file.length());
+ } catch (IOException e) {
+ Log.e(TAG, "Cannot calculate installed size " + file + ". Try only apk size.");
+ params.setSize(file.length());
+ }
+
mInstallHandler.post(new Runnable() {
@Override
public void run() {
diff --git a/src/com/android/packageinstaller/PackageInstallerActivity.java b/src/com/android/packageinstaller/PackageInstallerActivity.java
index 1903f91..55a1f81 100644
--- a/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -37,6 +37,7 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
+import android.os.Process;
import android.os.UserManager;
import android.provider.Settings;
import android.support.v4.view.ViewPager;
@@ -119,6 +120,9 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen
private static final int DLG_NOT_SUPPORTED_ON_WEAR = DLG_BASE + 7;
private void startInstallConfirm() {
+ ((TextView) findViewById(R.id.install_confirm_question))
+ .setText(R.string.install_confirm_question);
+ findViewById(R.id.spacer).setVisibility(View.GONE);
TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost);
tabHost.setup();
tabHost.setVisibility(View.VISIBLE);
@@ -323,7 +327,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen
// whether the untrusted sources setting is on. This allows partners to
// implement a "allow untrusted source once" feature.
if (request == REQUEST_ENABLE_UNKNOWN_SOURCES && result == RESULT_OK) {
- initiateInstall();
+ checkIfAllowedAndInitiateInstall(true);
} else {
clearCachedApkIfNeededAndFinish();
}
@@ -360,8 +364,8 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen
/**
* @return whether the device admin restricts installation from unknown sources
*/
- private boolean isUnknownSourcesAllowedByAdmin() {
- return !mUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
+ private boolean isUnknownSourcesDisallowed() {
+ return mUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
}
private void initiateInstall() {
@@ -453,27 +457,54 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen
mOk.setOnClickListener(this);
mCancel.setOnClickListener(this);
+ boolean wasSetUp = processPackageUri(packageUri);
+ if (!wasSetUp) {
+ return;
+ }
+
+ checkIfAllowedAndInitiateInstall(false);
+ }
+
+ /**
+ * Check if it is allowed to install the package and initiate install if allowed. If not allowed
+ * show the appropriate dialog.
+ *
+ * @param ignoreUnknownSourcesSettings Ignore {@link #isUnknownSourcesEnabled()} and proceed
+ * even if this would prevented installation.
+ */
+ private void checkIfAllowedAndInitiateInstall(boolean ignoreUnknownSourcesSettings) {
// Block the install attempt on the Unknown Sources setting if necessary.
- final boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent);
+ final boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(getIntent());
if (!requestFromUnknownSource) {
- processPackageUri(packageUri);
- return;
+ initiateInstall();
}
// If the admin prohibits it, or we're running in a managed profile, just show error
// and exit. Otherwise show an option to take the user to Settings to change the setting.
final boolean isManagedProfile = mUserManager.isManagedProfile();
- if (!isUnknownSourcesAllowedByAdmin()) {
- startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
- clearCachedApkIfNeededAndFinish();
+ if (isUnknownSourcesDisallowed()) {
+ if ((mUserManager.getUserRestrictionSource(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ Process.myUserHandle()) & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
+ if (ignoreUnknownSourcesSettings) {
+ initiateInstall();
+ } else {
+ showDialogInner(DLG_UNKNOWN_SOURCES);
+ }
+ } else {
+ startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
+ clearCachedApkIfNeededAndFinish();
+ }
} else if (!isUnknownSourcesEnabled() && isManagedProfile) {
showDialogInner(DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES);
} else if (!isUnknownSourcesEnabled()) {
- // Ask user to enable setting first
-
- showDialogInner(DLG_UNKNOWN_SOURCES);
+ if (ignoreUnknownSourcesSettings) {
+ initiateInstall();
+ } else {
+ // Ask user to enable setting first
+ showDialogInner(DLG_UNKNOWN_SOURCES);
+ }
} else {
- processPackageUri(packageUri);
+ initiateInstall();
}
}
@@ -486,7 +517,14 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen
super.onDestroy();
}
- private void processPackageUri(final Uri packageUri) {
+ /**
+ * Parse the Uri and set up the installer for this package.
+ *
+ * @param packageUri The URI to parse
+ *
+ * @return {@code true} iff the installer could be set up
+ */
+ private boolean processPackageUri(final Uri packageUri) {
mPackageURI = packageUri;
final String scheme = packageUri.getScheme();
@@ -505,7 +543,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen
+ " not available. Discontinuing installation");
showDialogInner(DLG_PACKAGE_ERROR);
setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
- return;
+ return false;
}
as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo),
mPm.getApplicationIcon(mPkgInfo.applicationInfo));
@@ -520,7 +558,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen
Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
showDialogInner(DLG_PACKAGE_ERROR);
setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
- return;
+ return false;
}
mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
PackageManager.GET_PERMISSIONS, 0, 0, null,
@@ -531,20 +569,20 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen
case SCHEME_CONTENT: {
mStagingAsynTask = new StagingAsyncTask();
mStagingAsynTask.execute(packageUri);
- return;
+ return false;
}
default: {
Log.w(TAG, "Unsupported scheme " + scheme);
setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);
clearCachedApkIfNeededAndFinish();
- return;
+ return false;
}
}
PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
- initiateInstall();
+ return true;
}
/** Get the ApplicationInfo for the calling package, if available */
@@ -770,7 +808,11 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen
}
mContentUriApkStagingFile = file;
Uri fileUri = Uri.fromFile(file);
- processPackageUri(fileUri);
+
+ boolean wasSetUp = processPackageUri(fileUri);
+ if (wasSetUp) {
+ checkIfAllowedAndInitiateInstall(false);
+ }
}
@Override
diff --git a/src/com/android/packageinstaller/permission/model/AppPermissionGroup.java b/src/com/android/packageinstaller/permission/model/AppPermissionGroup.java
index 2bdae42..aa68959 100755..100644
--- a/src/com/android/packageinstaller/permission/model/AppPermissionGroup.java
+++ b/src/com/android/packageinstaller/permission/model/AppPermissionGroup.java
@@ -286,6 +286,28 @@ public final class AppPermissionGroup implements Comparable<AppPermissionGroup>
return mPermissions.get(permission) != null;
}
+ public boolean checkRuntimePermission(String[] filterPermissions) {
+ if (LocationUtils.isLocationGroupAndProvider(mName, mPackageInfo.packageName)) {
+ return LocationUtils.isLocationEnabled(mContext);
+ }
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (filterPermissions != null
+ && !ArrayUtils.contains(filterPermissions, permission.getName())) {
+ continue;
+ }
+ if (mAppSupportsRuntimePermissions) {
+ if (!permission.isGranted()) {
+ return false;
+ }
+ } else if (permission.isGranted() && (permission.getAppOp() == null
+ || permission.isAppOpAllowed())) {
+ return true;
+ }
+ }
+ return false;
+ }
public boolean areRuntimePermissionsGranted() {
return areRuntimePermissionsGranted(null);
}
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
index 4a4b755..48d8dbb 100644
--- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
+++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
@@ -49,6 +49,7 @@ import com.android.packageinstaller.permission.ui.handheld.GrantPermissionsViewH
import com.android.packageinstaller.permission.utils.SafetyNetLogger;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
@@ -92,6 +93,7 @@ public class GrantPermissionsActivity extends OverlayTouchActivity
final int requestedPermCount = mRequestedPermissions.length;
mGrantResults = new int[requestedPermCount];
+ Arrays.fill(mGrantResults, PackageManager.PERMISSION_DENIED);
if (requestedPermCount == 0) {
setResultAndFinish();
@@ -161,12 +163,22 @@ public class GrantPermissionsActivity extends OverlayTouchActivity
break;
default: {
- if (!group.areRuntimePermissionsGranted()) {
- mRequestGrantPermissionGroups.put(group.getName(),
- new GroupState(group));
+ if (AppPermissionGroup.isStrictOpEnable()) {
+ if (!group.checkRuntimePermission(null)) {
+ mRequestGrantPermissionGroups.put(group.getName(),
+ new GroupState(group));
+ } else {
+ group.grantRuntimePermissions(false);
+ updateGrantResults(group);
+ }
} else {
- group.grantRuntimePermissions(false);
- updateGrantResults(group);
+ if (!group.areRuntimePermissionsGranted()) {
+ mRequestGrantPermissionGroups.put(group.getName(),
+ new GroupState(group));
+ } else {
+ group.grantRuntimePermissions(false);
+ updateGrantResults(group);
+ }
}
}
break;
@@ -197,10 +209,12 @@ public class GrantPermissionsActivity extends OverlayTouchActivity
// window height needed to show all content. We have to
// re-add the window to force it to be resized if needed.
View decor = getWindow().getDecorView();
- getWindowManager().removeViewImmediate(decor);
- getWindowManager().addView(decor, decor.getLayoutParams());
- if (mViewHandler instanceof GrantPermissionsViewHandlerImpl) {
- ((GrantPermissionsViewHandlerImpl) mViewHandler).onConfigurationChanged();
+ if (decor.getParent() != null) {
+ getWindowManager().removeViewImmediate(decor);
+ getWindowManager().addView(decor, decor.getLayoutParams());
+ if (mViewHandler instanceof GrantPermissionsViewHandlerImpl) {
+ ((GrantPermissionsViewHandlerImpl) mViewHandler).onConfigurationChanged();
+ }
}
}
@@ -297,7 +311,9 @@ public class GrantPermissionsActivity extends OverlayTouchActivity
groupState.mGroup.grantRuntimePermissions(doNotAskAgain);
groupState.mState = GroupState.STATE_ALLOWED;
} else {
- groupState.mGroup.revokeRuntimePermissions(doNotAskAgain);
+ if(!AppPermissionGroup.isStrictOpEnable()){
+ groupState.mGroup.revokeRuntimePermissions(doNotAskAgain);
+ }
groupState.mState = GroupState.STATE_DENIED;
}
updateGrantResults(groupState.mGroup);
diff --git a/src/com/android/packageinstaller/permission/ui/ManualLayoutFrame.java b/src/com/android/packageinstaller/permission/ui/ManualLayoutFrame.java
index a20c952..0b07c80 100644
--- a/src/com/android/packageinstaller/permission/ui/ManualLayoutFrame.java
+++ b/src/com/android/packageinstaller/permission/ui/ManualLayoutFrame.java
@@ -61,8 +61,13 @@ public class ManualLayoutFrame extends ViewGroup {
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ // We want to keep the content bottom at the same place to avoid movement of the "Allow"
+ // button.
+ // Try to keep the content bottom at the same height. If this would move the dialog out of
+ // the top of the screen move it down as much as possible, then keep it at that position for
+ // the rest of the sequence of permission dialogs.
View content = getChildAt(0);
- if (mContentBottom == 0) {
+ if (mContentBottom == 0 || content.getMeasuredHeight() > mContentBottom) {
mContentBottom = (getMeasuredHeight() + content.getMeasuredHeight()) / 2;
}
final int contentLeft = (getMeasuredWidth() - content.getMeasuredWidth()) / 2;
diff --git a/src/com/android/packageinstaller/permission/ui/OverlayTouchActivity.java b/src/com/android/packageinstaller/permission/ui/OverlayTouchActivity.java
index b23ab2e..a7800ca 100644
--- a/src/com/android/packageinstaller/permission/ui/OverlayTouchActivity.java
+++ b/src/com/android/packageinstaller/permission/ui/OverlayTouchActivity.java
@@ -40,6 +40,8 @@ public class OverlayTouchActivity extends Activity {
if (appOpsManager != null) {
appOpsManager.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
!allowed, mToken);
+ appOpsManager.setUserRestriction(AppOpsManager.OP_TOAST_WINDOW,
+ !allowed, mToken);
}
}
}
diff --git a/src/com/android/packageinstaller/permission/ui/SecureButtonView.java b/src/com/android/packageinstaller/permission/ui/SecureButtonView.java
deleted file mode 100644
index 624744e..0000000
--- a/src/com/android/packageinstaller/permission/ui/SecureButtonView.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.packageinstaller.permission.ui;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.Button;
-
-/**
- * Extension of Button that uses the hidden MotionEvent flag for partially obscured windows to
- * prevent tapjacking attacks.
- */
-public class SecureButtonView extends Button {
-
- public SecureButtonView(Context context) {
- this(context, null);
- }
-
- public SecureButtonView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public SecureButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public SecureButtonView(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- @Override
- public boolean onFilterTouchEventForSecurity(MotionEvent event) {
- if ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0
- || (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED) != 0) {
- // Window is obscured, drop this touch.
- return false;
- }
- return true;
- }
-}
diff --git a/src/com/android/packageinstaller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.java b/src/com/android/packageinstaller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.java
index 3d677d6..713b3e2 100755
--- a/src/com/android/packageinstaller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.java
+++ b/src/com/android/packageinstaller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.java
@@ -339,7 +339,7 @@ public final class GrantPermissionsViewHandlerImpl
if (mResultListener != null) {
view.clearAccessibilityFocus();
mResultListener.onPermissionGrantResult(mGroupName, false,
- AppPermissionGroup.isStrictOpEnable()? false: mDoNotAskCheckbox.isChecked());
+ AppPermissionGroup.isStrictOpEnable()? false: mShowDonNotAsk && mDoNotAskCheckbox.isChecked());
}
break;
case R.id.do_not_ask_checkbox:
diff --git a/src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java b/src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java
index df0bdd4..8fe96c9 100644
--- a/src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java
@@ -34,9 +34,6 @@ 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;
@@ -81,6 +78,7 @@ public final class PermissionAppsFragment extends PermissionsFrameFragment imple
private boolean mHasConfirmedRevoke;
private boolean mShowSystem;
+ private boolean mHasSystemApps;
private MenuItem mShowSystemMenu;
private MenuItem mHideSystemMenu;
@@ -110,13 +108,16 @@ public final class PermissionAppsFragment extends PermissionsFrameFragment imple
@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);
+ if (mHasSystemApps) {
+ 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();
+ }
+
HelpUtils.prepareHelpMenuItem(getActivity(), menu, R.string.help_app_permissions,
getClass().getName());
- updateMenu();
}
@Override
@@ -176,6 +177,8 @@ public final class PermissionAppsFragment extends PermissionsFrameFragment imple
setPreferenceScreen(screen);
}
+ screen.setOrderingAsAdded(false);
+
ArraySet<String> preferencesToRemove = new ArraySet<>();
for (int i = 0, n = screen.getPreferenceCount(); i < n; i++) {
preferencesToRemove.add(screen.getPreference(i).getKey());
@@ -186,11 +189,18 @@ public final class PermissionAppsFragment extends PermissionsFrameFragment imple
}
}
+ mHasSystemApps = false;
+ boolean menuOptionsInvalided = false;
+
for (PermissionApp app : permissionApps.getApps()) {
if (!Utils.shouldShowPermission(app)) {
continue;
}
+ if (!app.getAppInfo().enabled) {
+ continue;
+ }
+
String key = app.getKey();
preferencesToRemove.remove(key);
Preference existingPref = screen.findPreference(key);
@@ -199,6 +209,13 @@ public final class PermissionAppsFragment extends PermissionsFrameFragment imple
}
boolean isSystemApp = Utils.isSystem(app, mLauncherPkgs);
+
+ if (isSystemApp && !menuOptionsInvalided) {
+ mHasSystemApps = true;
+ getActivity().invalidateOptionsMenu();
+ menuOptionsInvalided = true;
+ }
+
if (isSystemApp && !isTelevision && !mShowSystem) {
if (existingPref != null) {
screen.removePreference(existingPref);
diff --git a/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java b/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java
index 29839c1..ec32070 100644
--- a/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java
@@ -81,6 +81,7 @@ public final class PermissionAppsFragment extends SettingsWithHeader implements
private boolean mHasConfirmedRevoke;
private boolean mShowSystem;
+ private boolean mHasSystemApps;
private MenuItem mShowSystemMenu;
private MenuItem mHideSystemMenu;
@@ -110,11 +111,13 @@ public final class PermissionAppsFragment extends SettingsWithHeader implements
@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();
+ if (mHasSystemApps) {
+ 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
@@ -184,6 +187,9 @@ public final class PermissionAppsFragment extends SettingsWithHeader implements
}
}
+ mHasSystemApps = false;
+ boolean menuOptionsInvalided = false;
+
for (PermissionApp app : permissionApps.getApps()) {
if (!Utils.shouldShowPermission(app)) {
continue;
@@ -197,6 +203,13 @@ public final class PermissionAppsFragment extends SettingsWithHeader implements
}
boolean isSystemApp = Utils.isSystem(app, mLauncherPkgs);
+
+ if (isSystemApp && !menuOptionsInvalided) {
+ mHasSystemApps = true;
+ getActivity().invalidateOptionsMenu();
+ menuOptionsInvalided = true;
+ }
+
if (isSystemApp && !isTelevision && !mShowSystem) {
if (existingPref != null) {
screen.removePreference(existingPref);
diff --git a/src/com/android/packageinstaller/wear/InstallTask.java b/src/com/android/packageinstaller/wear/InstallTask.java
new file mode 100644
index 0000000..53a460d
--- /dev/null
+++ b/src/com/android/packageinstaller/wear/InstallTask.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.packageinstaller.wear;
+
+import android.content.Context;
+import android.content.IntentSender;
+import android.content.pm.PackageInstaller;
+import android.os.Looper;
+import android.os.ParcelFileDescriptor;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Task that installs an APK. This must not be called on the main thread.
+ * This code is based off the Finsky/Wearsky implementation
+ */
+public class InstallTask {
+ private static final String TAG = "InstallTask";
+
+ private static final int DEFAULT_BUFFER_SIZE = 8192;
+
+ private final Context mContext;
+ private String mPackageName;
+ private ParcelFileDescriptor mParcelFileDescriptor;
+ private PackageInstallerImpl.InstallListener mCallback;
+ private PackageInstaller.Session mSession;
+ private IntentSender mCommitCallback;
+
+ private Exception mException = null;
+ private int mErrorCode = 0;
+ private String mErrorDesc = null;
+
+ public InstallTask(Context context, String packageName,
+ ParcelFileDescriptor parcelFileDescriptor,
+ PackageInstallerImpl.InstallListener callback, PackageInstaller.Session session,
+ IntentSender commitCallback) {
+ mContext = context;
+ mPackageName = packageName;
+ mParcelFileDescriptor = parcelFileDescriptor;
+ mCallback = callback;
+ mSession = session;
+ mCommitCallback = commitCallback;
+ }
+
+ public boolean isError() {
+ return mErrorCode != InstallerConstants.STATUS_SUCCESS || !TextUtils.isEmpty(mErrorDesc);
+ }
+
+ public void execute() {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ throw new IllegalStateException("This method cannot be called from the UI thread.");
+ }
+
+ OutputStream sessionStream = null;
+ try {
+ sessionStream = mSession.openWrite(mPackageName, 0, -1);
+
+ // 2b: Stream the asset to the installer. Note:
+ // Note: writeToOutputStreamFromAsset() always safely closes the input stream
+ writeToOutputStreamFromAsset(sessionStream);
+ mSession.fsync(sessionStream);
+ } catch (Exception e) {
+ mException = e;
+ mErrorCode = InstallerConstants.ERROR_INSTALL_COPY_STREAM;
+ mErrorDesc = "Could not write to stream";
+ } finally {
+ if (sessionStream != null) {
+ // 2c: close output stream
+ try {
+ sessionStream.close();
+ } catch (Exception e) {
+ // Ignore otherwise
+ if (mException == null) {
+ mException = e;
+ mErrorCode = InstallerConstants.ERROR_INSTALL_CLOSE_STREAM;
+ mErrorDesc = "Could not close session stream";
+ }
+ }
+ }
+ }
+
+ if (mErrorCode != InstallerConstants.STATUS_SUCCESS) {
+ // An error occurred, we're done
+ Log.e(TAG, "Exception while installing " + mPackageName + ": " + mErrorCode + ", "
+ + mErrorDesc + ", " + mException);
+ mSession.close();
+ mCallback.installFailed(mErrorCode, "[" + mPackageName + "]" + mErrorDesc);
+ } else {
+ // 3. Commit the session (this actually installs it.) Session map
+ // will be cleaned up in the callback.
+ mCallback.installBeginning();
+ mSession.commit(mCommitCallback);
+ mSession.close();
+ }
+ }
+
+ /**
+ * {@code PackageInstaller} works with streams. Get the {@code FileDescriptor}
+ * corresponding to the {@code Asset} and then write the contents into an
+ * {@code OutputStream} that is passed in.
+ * <br>
+ * The {@code FileDescriptor} is closed but the {@code OutputStream} is not closed.
+ */
+ private boolean writeToOutputStreamFromAsset(OutputStream outputStream) {
+ if (outputStream == null) {
+ mErrorCode = InstallerConstants.ERROR_INSTALL_COPY_STREAM_EXCEPTION;
+ mErrorDesc = "Got a null OutputStream.";
+ return false;
+ }
+
+ if (mParcelFileDescriptor == null || mParcelFileDescriptor.getFileDescriptor() == null) {
+ mErrorCode = InstallerConstants.ERROR_COULD_NOT_GET_FD;
+ mErrorDesc = "Could not get FD";
+ return false;
+ }
+
+ InputStream inputStream = null;
+ try {
+ byte[] inputBuf = new byte[DEFAULT_BUFFER_SIZE];
+ int bytesRead;
+ inputStream = new ParcelFileDescriptor.AutoCloseInputStream(mParcelFileDescriptor);
+
+ while ((bytesRead = inputStream.read(inputBuf)) > -1) {
+ if (bytesRead > 0) {
+ outputStream.write(inputBuf, 0, bytesRead);
+ }
+ }
+
+ outputStream.flush();
+ } catch (IOException e) {
+ mErrorCode = InstallerConstants.ERROR_INSTALL_APK_COPY_FAILURE;
+ mErrorDesc = "Reading from Asset FD or writing to temp file failed: " + e;
+ return false;
+ } finally {
+ safeClose(inputStream);
+ }
+
+ return true;
+ }
+
+ /**
+ * Quietly close a closeable resource (e.g. a stream or file). The input may already
+ * be closed and it may even be null.
+ */
+ public static void safeClose(Closeable resource) {
+ if (resource != null) {
+ try {
+ resource.close();
+ } catch (IOException ioe) {
+ // Catch and discard the error
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/packageinstaller/wear/InstallerConstants.java b/src/com/android/packageinstaller/wear/InstallerConstants.java
new file mode 100644
index 0000000..3daf3d8
--- /dev/null
+++ b/src/com/android/packageinstaller/wear/InstallerConstants.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.packageinstaller.wear;
+
+/**
+ * Constants for Installation / Uninstallation requests.
+ * Using the same values as Finsky/Wearsky code for consistency in user analytics of failures
+ */
+public class InstallerConstants {
+ /** Request succeeded */
+ public static final int STATUS_SUCCESS = 0;
+
+ /**
+ * The new PackageInstaller also returns a small set of less granular error codes, which
+ * we'll remap to the range -500 and below to keep away from existing installer codes
+ * (which run from -1 to -110).
+ */
+ public final static int ERROR_PACKAGEINSTALLER_BASE = -500;
+
+ public static final int ERROR_COULD_NOT_GET_FD = -603;
+ /** This node is not targeted by this request. */
+
+ /** The install did not complete because could not create PackageInstaller session */
+ public final static int ERROR_INSTALL_CREATE_SESSION = -612;
+ /** The install did not complete because could not open PackageInstaller session */
+ public final static int ERROR_INSTALL_OPEN_SESSION = -613;
+ /** The install did not complete because could not open PackageInstaller output stream */
+ public final static int ERROR_INSTALL_OPEN_STREAM = -614;
+ /** The install did not complete because of an exception while streaming bytes */
+ public final static int ERROR_INSTALL_COPY_STREAM_EXCEPTION = -615;
+ /** The install did not complete because of an unexpected exception from PackageInstaller */
+ public final static int ERROR_INSTALL_SESSION_EXCEPTION = -616;
+ /** The install did not complete because of an unexpected userActionRequired callback */
+ public final static int ERROR_INSTALL_USER_ACTION_REQUIRED = -617;
+ /** The install did not complete because of an unexpected broadcast (missing fields) */
+ public final static int ERROR_INSTALL_MALFORMED_BROADCAST = -618;
+ /** The install did not complete because of an error while copying from downloaded file */
+ public final static int ERROR_INSTALL_APK_COPY_FAILURE = -619;
+ /** The install did not complete because of an error while copying to the PackageInstaller
+ * output stream */
+ public final static int ERROR_INSTALL_COPY_STREAM = -620;
+ /** The install did not complete because of an error while closing the PackageInstaller
+ * output stream */
+ public final static int ERROR_INSTALL_CLOSE_STREAM = -621;
+} \ No newline at end of file
diff --git a/src/com/android/packageinstaller/wear/PackageInstallerFactory.java b/src/com/android/packageinstaller/wear/PackageInstallerFactory.java
new file mode 100644
index 0000000..bdc22cf
--- /dev/null
+++ b/src/com/android/packageinstaller/wear/PackageInstallerFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.packageinstaller.wear;
+
+import android.content.Context;
+
+/**
+ * Factory that creates a Package Installer.
+ */
+public class PackageInstallerFactory {
+ private static PackageInstallerImpl sPackageInstaller;
+
+ /**
+ * Return the PackageInstaller shared object. {@code init} should have already been called.
+ */
+ public synchronized static PackageInstallerImpl getPackageInstaller(Context context) {
+ if (sPackageInstaller == null) {
+ sPackageInstaller = new PackageInstallerImpl(context);
+ }
+ return sPackageInstaller;
+ }
+} \ No newline at end of file
diff --git a/src/com/android/packageinstaller/wear/PackageInstallerImpl.java b/src/com/android/packageinstaller/wear/PackageInstallerImpl.java
new file mode 100644
index 0000000..3dee781
--- /dev/null
+++ b/src/com/android/packageinstaller/wear/PackageInstallerImpl.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.packageinstaller.wear;
+
+import android.annotation.TargetApi;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.PackageInstaller;
+import android.os.Build;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Implementation of package manager installation using modern PackageInstaller api.
+ *
+ * Heavily copied from Wearsky/Finsky implementation
+ */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class PackageInstallerImpl {
+ private static final String TAG = "PackageInstallerImpl";
+
+ /** Intent actions used for broadcasts from PackageInstaller back to the local receiver */
+ private static final String ACTION_INSTALL_COMMIT =
+ "com.android.vending.INTENT_PACKAGE_INSTALL_COMMIT";
+
+ private final Context mContext;
+ private final PackageInstaller mPackageInstaller;
+ private final Map<String, PackageInstaller.SessionInfo> mSessionInfoMap;
+ private final Map<String, PackageInstaller.Session> mOpenSessionMap;
+
+ public PackageInstallerImpl(Context context) {
+ mContext = context.getApplicationContext();
+ mPackageInstaller = mContext.getPackageManager().getPackageInstaller();
+
+ // Capture a map of known sessions
+ // This list will be pruned a bit later (stale sessions will be canceled)
+ mSessionInfoMap = new HashMap<String, PackageInstaller.SessionInfo>();
+ List<PackageInstaller.SessionInfo> mySessions = mPackageInstaller.getMySessions();
+ for (int i = 0; i < mySessions.size(); i++) {
+ PackageInstaller.SessionInfo sessionInfo = mySessions.get(i);
+ String packageName = sessionInfo.getAppPackageName();
+ PackageInstaller.SessionInfo oldInfo = mSessionInfoMap.put(packageName, sessionInfo);
+
+ // Checking for old info is strictly for logging purposes
+ if (oldInfo != null) {
+ Log.w(TAG, "Multiple sessions for " + packageName + " found. Removing " + oldInfo
+ .getSessionId() + " & keeping " + mySessions.get(i).getSessionId());
+ }
+ }
+ mOpenSessionMap = new HashMap<String, PackageInstaller.Session>();
+ }
+
+ /**
+ * This callback will be made after an installation attempt succeeds or fails.
+ */
+ public interface InstallListener {
+ /**
+ * This callback signals that preflight checks have succeeded and installation
+ * is beginning.
+ */
+ void installBeginning();
+
+ /**
+ * This callback signals that installation has completed.
+ */
+ void installSucceeded();
+
+ /**
+ * This callback signals that installation has failed.
+ */
+ void installFailed(int errorCode, String errorDesc);
+ }
+
+ /**
+ * This is a placeholder implementation that bundles an entire "session" into a single
+ * call. This will be replaced by more granular versions that allow longer session lifetimes,
+ * download progress tracking, etc.
+ *
+ * This must not be called on main thread.
+ */
+ public void install(final String packageName, ParcelFileDescriptor parcelFileDescriptor,
+ final InstallListener callback) {
+ // 0. Generic try/catch block because I am not really sure what exceptions (other than
+ // IOException) might be thrown by PackageInstaller and I want to handle them
+ // at least slightly gracefully.
+ try {
+ // 1. Create or recover a session, and open it
+ // Try recovery first
+ PackageInstaller.Session session = null;
+ PackageInstaller.SessionInfo sessionInfo = mSessionInfoMap.get(packageName);
+ if (sessionInfo != null) {
+ // See if it's openable, or already held open
+ session = getSession(packageName);
+ }
+ // If open failed, or there was no session, create a new one and open it.
+ // If we cannot create or open here, the failure is terminal.
+ if (session == null) {
+ try {
+ innerCreateSession(packageName);
+ } catch (IOException ioe) {
+ Log.e(TAG, "Can't create session for " + packageName + ": " + ioe.getMessage());
+ callback.installFailed(InstallerConstants.ERROR_INSTALL_CREATE_SESSION,
+ "Could not create session");
+ mSessionInfoMap.remove(packageName);
+ return;
+ }
+ sessionInfo = mSessionInfoMap.get(packageName);
+ try {
+ session = mPackageInstaller.openSession(sessionInfo.getSessionId());
+ mOpenSessionMap.put(packageName, session);
+ } catch (SecurityException se) {
+ Log.e(TAG, "Can't open session for " + packageName + ": " + se.getMessage());
+ callback.installFailed(InstallerConstants.ERROR_INSTALL_OPEN_SESSION,
+ "Can't open session");
+ mSessionInfoMap.remove(packageName);
+ return;
+ }
+ }
+
+ // 2. Launch task to handle file operations.
+ InstallTask task = new InstallTask( mContext, packageName, parcelFileDescriptor,
+ callback, session,
+ getCommitCallback(packageName, sessionInfo.getSessionId(), callback));
+ task.execute();
+ if (task.isError()) {
+ cancelSession(sessionInfo.getSessionId(), packageName);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unexpected exception while installing " + packageName);
+ callback.installFailed(InstallerConstants.ERROR_INSTALL_SESSION_EXCEPTION,
+ "Unexpected exception while installing " + packageName);
+ }
+ }
+
+ /**
+ * Retrieve an existing session. Will open if needed, but does not attempt to create.
+ */
+ private PackageInstaller.Session getSession(String packageName) {
+ // Check for already-open session
+ PackageInstaller.Session session = mOpenSessionMap.get(packageName);
+ if (session != null) {
+ try {
+ // Probe the session to ensure that it's still open. This may or may not
+ // throw (if non-open), but it may serve as a canary for stale sessions.
+ session.getNames();
+ return session;
+ } catch (IOException ioe) {
+ Log.e(TAG, "Stale open session for " + packageName + ": " + ioe.getMessage());
+ mOpenSessionMap.remove(packageName);
+ } catch (SecurityException se) {
+ Log.e(TAG, "Stale open session for " + packageName + ": " + se.getMessage());
+ mOpenSessionMap.remove(packageName);
+ }
+ }
+ // Check to see if this is a known session
+ PackageInstaller.SessionInfo sessionInfo = mSessionInfoMap.get(packageName);
+ if (sessionInfo == null) {
+ return null;
+ }
+ // Try to open it. If we fail here, assume that the SessionInfo was stale.
+ try {
+ session = mPackageInstaller.openSession(sessionInfo.getSessionId());
+ } catch (SecurityException se) {
+ Log.w(TAG, "SessionInfo was stale for " + packageName + " - deleting info");
+ mSessionInfoMap.remove(packageName);
+ return null;
+ } catch (IOException ioe) {
+ Log.w(TAG, "IOException opening old session for " + ioe.getMessage()
+ + " - deleting info");
+ mSessionInfoMap.remove(packageName);
+ return null;
+ }
+ mOpenSessionMap.put(packageName, session);
+ return session;
+ }
+
+ /** This version throws an IOException when the session cannot be created */
+ private void innerCreateSession(String packageName) throws IOException {
+ if (mSessionInfoMap.containsKey(packageName)) {
+ Log.w(TAG, "Creating session for " + packageName + " when one already exists");
+ return;
+ }
+ PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+ PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ params.setAppPackageName(packageName);
+
+ // IOException may be thrown at this point
+ int sessionId = mPackageInstaller.createSession(params);
+ PackageInstaller.SessionInfo sessionInfo = mPackageInstaller.getSessionInfo(sessionId);
+ mSessionInfoMap.put(packageName, sessionInfo);
+ }
+
+ /**
+ * Cancel a session based on its sessionId. Package name is for logging only.
+ */
+ private void cancelSession(int sessionId, String packageName) {
+ // Close if currently held open
+ closeSession(packageName);
+ // Remove local record
+ mSessionInfoMap.remove(packageName);
+ try {
+ mPackageInstaller.abandonSession(sessionId);
+ } catch (SecurityException se) {
+ // The session no longer exists, so we can exit quietly.
+ return;
+ }
+ }
+
+ /**
+ * Close a session if it happens to be held open.
+ */
+ private void closeSession(String packageName) {
+ PackageInstaller.Session session = mOpenSessionMap.remove(packageName);
+ if (session != null) {
+ // Unfortunately close() is not idempotent. Try our best to make this safe.
+ try {
+ session.close();
+ } catch (Exception e) {
+ Log.w(TAG, "Unexpected error closing session for " + packageName + ": "
+ + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Creates a commit callback for the package install that's underway. This will be called
+ * some time after calling session.commit() (above).
+ */
+ private IntentSender getCommitCallback(final String packageName, final int sessionId,
+ final InstallListener callback) {
+ // Create a single-use broadcast receiver
+ BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mContext.unregisterReceiver(this);
+ handleCommitCallback(intent, packageName, sessionId, callback);
+ }
+ };
+ // Create a matching intent-filter and register the receiver
+ String action = ACTION_INSTALL_COMMIT + "." + packageName;
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(action);
+ mContext.registerReceiver(broadcastReceiver, intentFilter);
+
+ // Create a matching PendingIntent and use it to generate the IntentSender
+ Intent broadcastIntent = new Intent(action);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, packageName.hashCode(),
+ broadcastIntent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
+ return pendingIntent.getIntentSender();
+ }
+
+ /**
+ * Examine the extras to determine information about the package update/install, decode
+ * the result, and call the appropriate callback.
+ *
+ * @param intent The intent, which the PackageInstaller will have added Extras to
+ * @param packageName The package name we created the receiver for
+ * @param sessionId The session Id we created the receiver for
+ * @param callback The callback to report success/failure to
+ */
+ private void handleCommitCallback(Intent intent, String packageName, int sessionId,
+ InstallListener callback) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Installation of " + packageName + " finished with extras "
+ + intent.getExtras());
+ }
+ String statusMessage = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
+ int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, Integer.MIN_VALUE);
+ if (status == PackageInstaller.STATUS_SUCCESS) {
+ cancelSession(sessionId, packageName);
+ callback.installSucceeded();
+ } else if (status == -1 /*PackageInstaller.STATUS_USER_ACTION_REQUIRED*/) {
+ // TODO - use the constant when the correct/final name is in the SDK
+ // TODO This is unexpected, so we are treating as failure for now
+ cancelSession(sessionId, packageName);
+ callback.installFailed(InstallerConstants.ERROR_INSTALL_USER_ACTION_REQUIRED,
+ "Unexpected: user action required");
+ } else {
+ cancelSession(sessionId, packageName);
+ int errorCode = getPackageManagerErrorCode(status);
+ Log.e(TAG, "Error " + errorCode + " while installing " + packageName + ": "
+ + statusMessage);
+ callback.installFailed(errorCode, null);
+ }
+ }
+
+ private int getPackageManagerErrorCode(int status) {
+ // This is a hack: because PackageInstaller now reports error codes
+ // with small positive values, we need to remap them into a space
+ // that is more compatible with the existing package manager error codes.
+ // See https://sites.google.com/a/google.com/universal-store/documentation
+ // /android-client/download-error-codes
+ int errorCode;
+ if (status == Integer.MIN_VALUE) {
+ errorCode = InstallerConstants.ERROR_INSTALL_MALFORMED_BROADCAST;
+ } else {
+ errorCode = InstallerConstants.ERROR_PACKAGEINSTALLER_BASE - status;
+ }
+ return errorCode;
+ }
+} \ No newline at end of file
diff --git a/src/com/android/packageinstaller/wear/WearPackageArgs.java b/src/com/android/packageinstaller/wear/WearPackageArgs.java
index da49192..2c289b2 100644
--- a/src/com/android/packageinstaller/wear/WearPackageArgs.java
+++ b/src/com/android/packageinstaller/wear/WearPackageArgs.java
@@ -45,6 +45,8 @@ public class WearPackageArgs {
"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";
+ private static final String KEY_SKIP_IF_LOWER_VERSION =
+ "com.google.android.clockwork.EXTRA_SKIP_IF_LOWER_VERSION";
public static String getPackageName(Bundle b) {
return b.getString(KEY_PACKAGE_NAME);
@@ -87,6 +89,10 @@ public class WearPackageArgs {
return b.getInt(KEY_START_ID);
}
+ public static boolean skipIfLowerVersion(Bundle b) {
+ return b.getBoolean(KEY_SKIP_IF_LOWER_VERSION, false);
+ }
+
public static Bundle setStartId(Bundle b, int startId) {
b.putInt(KEY_START_ID, startId);
return b;
diff --git a/src/com/android/packageinstaller/wear/WearPackageInstallerService.java b/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
index 7387ed2..2d4744c 100644
--- a/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
+++ b/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
@@ -22,7 +22,6 @@ 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;
@@ -98,13 +97,6 @@ public class WearPackageInstallerService extends Service {
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;
@@ -203,13 +195,15 @@ public class WearPackageInstallerService extends Service {
int companionSdkVersion = WearPackageArgs.getCompanionSdkVersion(argsBundle);
int companionDeviceVersion = WearPackageArgs.getCompanionDeviceVersion(argsBundle);
String compressionAlg = WearPackageArgs.getCompressionAlg(argsBundle);
+ boolean skipIfLowerVersion = WearPackageArgs.skipIfLowerVersion(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);
+ companionSdkVersion + ", companionDeviceVersion: " + companionDeviceVersion +
+ ", skipIfLowerVersion: " + skipIfLowerVersion);
}
final PackageManager pm = getPackageManager();
File tempFile = null;
@@ -233,6 +227,12 @@ public class WearPackageInstallerService extends Service {
Log.d(TAG, "Replacing package:" + packageName);
}
}
+ // TODO(28021618): This was left as a temp file due to the fact that this code is being
+ // deprecated and that we need the bare minimum to continue working moving forward
+ // If this code is used as reference, this permission logic might want to be
+ // reworked to use a stream instead of a file so that we don't need to write a
+ // file at all. Note that there might be some trickiness with opening a stream
+ // for multiple users.
ParcelFileDescriptor parcelFd = getContentResolver()
.openFileDescriptor(assetUri, "r");
tempFile = WearPackageUtil.getFileFromFd(WearPackageInstallerService.this,
@@ -268,9 +268,17 @@ public class WearPackageInstallerService extends Service {
") 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);
+ if (skipIfLowerVersion) {
+ // Starting in Feldspar, we are not going to allow downgrades of any app.
+ Log.w(TAG, "Version number of new app (" + pkg.mVersionCode +
+ ") is lower than existing app ( " + existingPkgInfo.versionCode +
+ ") for " + packageName + "; not installing due to versionCheck");
+ return;
+ } else {
+ 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
@@ -318,9 +326,9 @@ public class WearPackageInstallerService extends Service {
}
// Finally install the package.
- pm.installPackage(Uri.fromFile(tempFile),
- new PackageInstallObserver(this, lock, startId, packageName),
- installFlags, packageName);
+ ParcelFileDescriptor fd = getContentResolver().openFileDescriptor(assetUri, "r");
+ PackageInstallerFactory.getPackageInstaller(this).install(packageName, fd,
+ new PackageInstallListener(this, lock, startId, packageName));
messageSent = true;
Log.i(TAG, "Sent installation request for " + packageName);
@@ -338,6 +346,10 @@ public class WearPackageInstallerService extends Service {
}
}
+ // TODO: This was left using the old PackageManager API due to the fact that this code is being
+ // deprecated and that we need the bare minimum to continue working moving forward
+ // If this code is used as reference, this logic should be reworked to use the new
+ // PackageInstaller APIs similar to how installPackage was reworked
private void uninstallPackage(Bundle argsBundle) {
int startId = WearPackageArgs.getStartId(argsBundle);
final String packageName = WearPackageArgs.getPackageName(argsBundle);
@@ -558,12 +570,12 @@ public class WearPackageInstallerService extends Service {
}
}
- private class PackageInstallObserver extends IPackageInstallObserver.Stub {
+ private class PackageInstallListener implements PackageInstallerImpl.InstallListener {
private Context mContext;
private PowerManager.WakeLock mWakeLock;
private int mStartId;
private String mApplicationPackageName;
- private PackageInstallObserver(Context context, PowerManager.WakeLock wakeLock,
+ private PackageInstallListener(Context context, PowerManager.WakeLock wakeLock,
int startId, String applicationPackageName) {
mContext = context;
mWakeLock = wakeLock;
@@ -571,35 +583,33 @@ public class WearPackageInstallerService extends Service {
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;
- }
+ @Override
+ public void installBeginning() {
+ Log.i(TAG, "Package " + mApplicationPackageName + " is being installed.");
+ }
- Log.i(TAG, "Package " + packageName + " was installed.");
+ @Override
+ public void installSucceeded() {
+ try {
+ Log.i(TAG, "Package " + mApplicationPackageName + " was installed.");
// Delete tempFile from the file system.
- File tempFile = WearPackageUtil.getTemporaryFile(mContext, packageName);
+ File tempFile = WearPackageUtil.getTemporaryFile(mContext, mApplicationPackageName);
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);
}
}
+
+ @Override
+ public void installFailed(int errorCode, String errorDesc) {
+ Log.e(TAG, "Package install failed " + mApplicationPackageName
+ + ", errorCode " + errorCode);
+ WearPackageUtil.removeFromPermStore(mContext, mApplicationPackageName);
+ finishService(mWakeLock, mStartId);
+ }
}
private class PackageDeleteObserver extends IPackageDeleteObserver.Stub {