diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index c74516d410b57db61b72631f01cf08ab88275da6..2df7042a53d917b7d93c64e1620de47c0bbd812a 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -5,6 +5,7 @@ checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPL core/tests/coretests/src/android/ packages/PrintRecommendationService/ packages/PrintSpooler/ + packages/PackageInstaller/ services/print/ services/usb/ telephony/ diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index ee752f8b818659258cb7d2a95cd221849db1d442..edddb7939ead18bca37944094454195ab871267a 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -48,6 +48,7 @@ public abstract class PackageManagerInternal { public static final int PACKAGE_VERIFIER = 3; public static final int PACKAGE_BROWSER = 4; public static final int PACKAGE_SYSTEM_TEXT_CLASSIFIER = 5; + public static final int PACKAGE_PERMISSION_CONTROLLER = 6; @IntDef(value = { PACKAGE_SYSTEM, PACKAGE_SETUP_WIZARD, @@ -55,6 +56,7 @@ public abstract class PackageManagerInternal { PACKAGE_VERIFIER, PACKAGE_BROWSER, PACKAGE_SYSTEM_TEXT_CLASSIFIER, + PACKAGE_PERMISSION_CONTROLLER, }) @Retention(RetentionPolicy.SOURCE) public @interface KnownPackage {} diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml index 4e09c69b6779f4dfed657e7f005ebbe15cf1068d..5cfae1170097df2344723b8428776012d9208313 100644 --- a/data/etc/hiddenapi-package-whitelist.xml +++ b/data/etc/hiddenapi-package-whitelist.xml @@ -38,7 +38,7 @@ platform cert need to be included, as apps signed with the platform cert are exe <hidden-api-whitelisted-app package="com.android.launcher3" /> <hidden-api-whitelisted-app package="com.android.mtp" /> <hidden-api-whitelisted-app package="com.android.musicfx" /> - <hidden-api-whitelisted-app package="com.android.packageinstaller" /> + <hidden-api-whitelisted-app package="com.android.permissioncontroller" /> <hidden-api-whitelisted-app package="com.android.printservice.recommendation" /> <hidden-api-whitelisted-app package="com.android.printspooler" /> <hidden-api-whitelisted-app package="com.android.providers.blockednumber" /> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 434af14ff44f8f5c5bd27ead7e48fb3397c67802..f6587d38d8571399605f4cd080a64c96adbad23d 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -133,13 +133,18 @@ applications that come with the platform </privapp-permissions> <privapp-permissions package="com.android.packageinstaller"> - <permission name="android.permission.CLEAR_APP_CACHE"/> <permission name="android.permission.DELETE_PACKAGES"/> <permission name="android.permission.INSTALL_PACKAGES"/> + <permission name="android.permission.USE_RESERVED_DISK"/> + <permission name="android.permission.MANAGE_USERS"/> + <permission name="android.permission.UPDATE_APP_OPS_STATS"/> + </privapp-permissions> + + <privapp-permissions package="com.android.permissioncontroller"> + <permission name="android.permission.CLEAR_APP_CACHE"/> <permission name="android.permission.MANAGE_USERS"/> <permission name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"/> <permission name="android.permission.UPDATE_APP_OPS_STATS"/> - <permission name="android.permission.USE_RESERVED_DISK"/> </privapp-permissions> <privapp-permissions package="com.android.phone"> diff --git a/packages/PackageInstaller/Android.mk b/packages/PackageInstaller/Android.mk index 65b82557bcb6fc1ba41110c41a3d8db582fc1bec..f556b48f27b160dee7cfe5b60b6e55d3f214a2c0 100644 --- a/packages/PackageInstaller/Android.mk +++ b/packages/PackageInstaller/Android.mk @@ -9,42 +9,16 @@ LOCAL_SRC_FILES := \ $(call all-java-files-under, src) LOCAL_STATIC_ANDROID_LIBRARIES += \ - androidx.car_car \ - androidx.design_design \ - androidx.transition_transition \ - androidx.core_core \ - androidx.media_media \ - androidx.legacy_legacy-support-core-utils \ - androidx.legacy_legacy-support-core-ui \ - androidx.fragment_fragment \ - androidx.appcompat_appcompat \ - androidx.preference_preference \ - androidx.recyclerview_recyclerview \ - androidx.legacy_legacy-preference-v14 \ - androidx.leanback_leanback \ - androidx.leanback_leanback-preference \ - SettingsLib + androidx.leanback_leanback LOCAL_STATIC_JAVA_LIBRARIES := \ xz-java \ androidx.annotation_annotation LOCAL_PACKAGE_NAME := PackageInstaller -LOCAL_CERTIFICATE := platform +LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true - -LOCAL_PROGUARD_FLAG_FILES := proguard.flags - -# Comment for now unitl all private API dependencies are removed -# LOCAL_SDK_VERSION := system_current LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) - -ifeq (PackageInstaller,$(LOCAL_PACKAGE_NAME)) - # Use the following include to make our test apk. - ifeq (,$(ONE_SHOT_MAKEFILE)) - include $(call all-makefiles-under,$(LOCAL_PATH)) - endif -endif diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml index 578207529880d7213b388e6b091376944fe2c79f..f4b9cefc99ce7b692eff966a4830538246193f7b 100644 --- a/packages/PackageInstaller/AndroidManifest.xml +++ b/packages/PackageInstaller/AndroidManifest.xml @@ -1,35 +1,20 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.packageinstaller" coreApp="true"> - - <original-package android:name="com.android.packageinstaller" /> + package="com.android.packageinstaller"> + <uses-permission android:name="android.permission.MANAGE_USERS" /> <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.DELETE_PACKAGES" /> - <uses-permission android:name="android.permission.CLEAR_APP_CACHE" /> - <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" /> - <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> - <uses-permission android:name="android.permission.MANAGE_USERS" /> - <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS" /> - <uses-permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS" /> - <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" /> - <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> - <uses-permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS" /> <uses-permission android:name="android.permission.READ_INSTALL_SESSIONS" /> - <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> - <uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES" /> - <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> - <uses-permission android:name="android.permission.WAKE_LOCK" /> - <uses-permission android:name="android.permission.KILL_UID" /> - <uses-permission android:name="android.permission.MANAGE_APP_OPS_RESTRICTIONS" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS" /> <uses-permission android:name="android.permission.USE_RESERVED_DISK" /> + <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> + <uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES" /> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <uses-permission android:name="com.google.android.permission.INSTALL_WEARABLE_PACKAGES" /> - <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS" /> - <application android:name=".PackageInstallerApplication" android:label="@string/app_name" android:allowBackup="false" @@ -131,56 +116,11 @@ android:configChanges="mnc|mnc|touchscreen|navigation|screenLayout|screenSize|smallestScreenSize|orientation|locale|keyboard|keyboardHidden|fontScale|uiMode|layoutDirection|density" android:exported="false" /> - <activity android:name=".permission.ui.GrantPermissionsActivity" - android:configChanges="keyboardHidden|screenSize" - android:excludeFromRecents="true" - android:theme="@style/GrantPermissions" - android:visibleToInstantApps="true"> - <intent-filter android:priority="1"> - <action android:name="android.content.pm.action.REQUEST_PERMISSIONS" /> - <category android:name="android.intent.category.DEFAULT" /> - </intent-filter> - </activity> - - <activity android:name=".permission.ui.ManagePermissionsActivity" - android:configChanges="orientation|keyboardHidden|screenSize" - android:label="@string/app_permissions" - android:theme="@style/Settings" - android:permission="android.permission.GRANT_RUNTIME_PERMISSIONS"> - <intent-filter android:priority="1"> - <action android:name="android.intent.action.MANAGE_PERMISSIONS" /> - <action android:name="android.intent.action.MANAGE_APP_PERMISSIONS" /> - <action android:name="android.intent.action.MANAGE_PERMISSION_APPS" /> - <category android:name="android.intent.category.DEFAULT" /> - </intent-filter> - </activity> - - <activity android:name=".permission.ui.ReviewPermissionsActivity" - android:excludeFromRecents="true" - android:theme="@style/Settings.NoActionBar" - android:permission="android.permission.GRANT_RUNTIME_PERMISSIONS"> - <intent-filter android:priority="1"> - <action android:name="android.intent.action.REVIEW_PERMISSIONS" /> - <category android:name="android.intent.category.DEFAULT" /> - </intent-filter> - </activity> - - <activity android:name=".permission.ui.OverlayWarningDialog" - android:excludeFromRecents="true" - android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar" /> - <!-- Wearable Components --> <service android:name=".wear.WearPackageInstallerService" android:permission="com.google.android.permission.INSTALL_WEARABLE_PACKAGES" android:exported="true"/> - <service android:name=".permission.service.RuntimePermissionPresenterServiceImpl" - android:permission="android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE"> - <intent-filter android:priority="1"> - <action android:name="android.permissionpresenterservice.RuntimePermissionPresenterService"/> - </intent-filter> - </service> - <provider android:name=".wear.WearPackageIconProvider" android:authorities="com.google.android.packageinstaller.wear.provider" android:grantUriPermissions="true" diff --git a/packages/PackageInstaller/PREUPLOAD.cfg b/packages/PackageInstaller/PREUPLOAD.cfg deleted file mode 100644 index 94e464042243db4e0ff5aa9e738a5dde0e56b1bf..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/PREUPLOAD.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[Builtin Hooks] -xmllint = true -commit_msg_changeid_field = true - -[Hook Scripts] -checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT} -strings_lint_hook = ${REPO_ROOT}/frameworks/base/tools/stringslint/stringslint_sha.sh ${PREUPLOAD_COMMIT} diff --git a/packages/PackageInstaller/proguard.flags b/packages/PackageInstaller/proguard.flags deleted file mode 100644 index 46a929e383e05caf65be83959b3e6063f3566155..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/proguard.flags +++ /dev/null @@ -1,8 +0,0 @@ -# The support library contains references to newer platform versions. -# Don't warn about those in case this app is linking against an older -# platform version. We know about them, and they are safe. - --keep class androidx.preference.Preference* { - *; -} --dontwarn androidx.core.** diff --git a/packages/PackageInstaller/res/color/btn_colored_background_material.xml b/packages/PackageInstaller/res/color/btn_colored_background_material.xml deleted file mode 100644 index a6cd0890706ab98e112681e6e070de504e5716cf..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/color/btn_colored_background_material.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_enabled="false" - android:alpha="?android:disabledAlpha" - android:color="?android:colorButtonNormal" /> - <item android:color="?android:colorAccent" /> -</selector> diff --git a/packages/PackageInstaller/res/drawable-hdpi/ic_fail.png b/packages/PackageInstaller/res/drawable-hdpi/ic_fail.png deleted file mode 100644 index 30f75632cb92f495a943fc6f9f4e1427399cdf9a..0000000000000000000000000000000000000000 Binary files a/packages/PackageInstaller/res/drawable-hdpi/ic_fail.png and /dev/null differ diff --git a/packages/PackageInstaller/res/drawable-hdpi/ic_success.png b/packages/PackageInstaller/res/drawable-hdpi/ic_success.png deleted file mode 100644 index f36d491a6be7e0e78fac93d5ecb1d4c53fca4fc3..0000000000000000000000000000000000000000 Binary files a/packages/PackageInstaller/res/drawable-hdpi/ic_success.png and /dev/null differ diff --git a/packages/PackageInstaller/res/drawable-hdpi/tab_unselected_holo.9.png b/packages/PackageInstaller/res/drawable-hdpi/tab_unselected_holo.9.png deleted file mode 100644 index 19532ab10d4fe414d597ed44ed50c91a3e3b9279..0000000000000000000000000000000000000000 Binary files a/packages/PackageInstaller/res/drawable-hdpi/tab_unselected_holo.9.png and /dev/null differ diff --git a/packages/PackageInstaller/res/drawable-mdpi/ic_fail.png b/packages/PackageInstaller/res/drawable-mdpi/ic_fail.png deleted file mode 100644 index 12e269ea4fa664b4f8db5f48715368b67b250468..0000000000000000000000000000000000000000 Binary files a/packages/PackageInstaller/res/drawable-mdpi/ic_fail.png and /dev/null differ diff --git a/packages/PackageInstaller/res/drawable-mdpi/ic_success.png b/packages/PackageInstaller/res/drawable-mdpi/ic_success.png deleted file mode 100644 index 51aab2e74242772a785f6ed6d87c3d6fe13c369f..0000000000000000000000000000000000000000 Binary files a/packages/PackageInstaller/res/drawable-mdpi/ic_success.png and /dev/null differ diff --git a/packages/PackageInstaller/res/drawable-mdpi/tab_unselected_holo.9.png b/packages/PackageInstaller/res/drawable-mdpi/tab_unselected_holo.9.png deleted file mode 100644 index a2dbf42b74f7fafb6d8a057306a9c021867d035c..0000000000000000000000000000000000000000 Binary files a/packages/PackageInstaller/res/drawable-mdpi/tab_unselected_holo.9.png and /dev/null differ diff --git a/packages/PackageInstaller/res/drawable-television/grant_permissions_action_item.xml b/packages/PackageInstaller/res/drawable-television/grant_permissions_action_item.xml deleted file mode 100644 index 96bf582c9beab11db019e7aa28dd8846c089153b..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable-television/grant_permissions_action_item.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<ripple xmlns:android="http://schemas.android.com/apk/res/android" - android:color="@color/grant_permissions_white_text_alpha_100"> - <item android:drawable="@drawable/grant_permissions_action_item_background" /> -</ripple> diff --git a/packages/PackageInstaller/res/drawable-television/grant_permissions_action_item_background.xml b/packages/PackageInstaller/res/drawable-television/grant_permissions_action_item_background.xml deleted file mode 100644 index 86d6b1f48a38971ed6fb82013be8c175bf6f575d..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable-television/grant_permissions_action_item_background.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="true" android:drawable="@drawable/grant_permissions_action_item_shape" /> - <item android:state_focused="true" android:drawable="@drawable/grant_permissions_action_item_shape" /> - <!-- no default background is specified, making the button transparent when not active --> -</selector> diff --git a/packages/PackageInstaller/res/drawable-television/grant_permissions_action_item_shape.xml b/packages/PackageInstaller/res/drawable-television/grant_permissions_action_item_shape.xml deleted file mode 100644 index 08cd3455949a34e5080575c15e285347a5bda6ec..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable-television/grant_permissions_action_item_shape.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<inset xmlns:android="http://schemas.android.com/apk/res/android" - android:insetRight="1dp" - android:insetBottom="1dp"> - <shape android:shape="rectangle"> - <corners android:radius="2dp" /> - <solid android:color="@color/grant_permissions_focus_highlight" /> - <padding android:left="8dp" - android:top="4dp" - android:right="8dp" - android:bottom="4dp" /> - </shape> -</inset> diff --git a/packages/PackageInstaller/res/drawable-watch/accept_deny_dialog_negative_bg.xml b/packages/PackageInstaller/res/drawable-watch/accept_deny_dialog_negative_bg.xml deleted file mode 100644 index 1ccc40abc80454593dd62ca30037b89c6c60f9f2..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable-watch/accept_deny_dialog_negative_bg.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- 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. ---> -<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> - <item> - <ripple android:color="?android:colorControlHighlight" /> - </item> - <item> - <ripple android:color="?android:colorControlHighlight"> - <item> - <shape android:shape="oval" - android:tint="?android:colorButtonNormal"> - <solid android:color="@android:color/white" /> - <size android:width="@dimen/diag_button_size" - android:height="@dimen/diag_button_size" /> - </shape> - </item> - </ripple> - </item> -</layer-list> diff --git a/packages/PackageInstaller/res/drawable-watch/accept_deny_dialog_positive_bg.xml b/packages/PackageInstaller/res/drawable-watch/accept_deny_dialog_positive_bg.xml deleted file mode 100644 index 786a35ba21c6fc5f1b5a0883e9349572a2f2fb3e..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable-watch/accept_deny_dialog_positive_bg.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- 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. ---> -<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> - <item> - <ripple android:color="?android:colorAccent" /> - </item> - <item> - <ripple android:color="?android:colorControlHighlight"> - <item> - <shape android:shape="oval" - android:tint="@color/btn_colored_background_material"> - <solid android:color="@android:color/white" /> - <size android:width="@dimen/diag_button_size" - android:height="@dimen/diag_button_size" /> - </shape> - </item> - </ripple> - </item> -</layer-list> diff --git a/packages/PackageInstaller/res/drawable-watch/action_negative_bg.xml b/packages/PackageInstaller/res/drawable-watch/action_negative_bg.xml deleted file mode 100644 index 994ae8e2d4a85f50249a1ff978d46c033c2ce21d..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable-watch/action_negative_bg.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<ripple xmlns:android="http://schemas.android.com/apk/res/android" - android:color="?android:colorControlHighlight"> - <item> - <shape android:shape="oval" android:tint="?android:colorButtonNormal"> - <solid android:color="@android:color/white" /> - <size android:width="40dp" android:height="40dp" /> - </shape> - </item> -</ripple> diff --git a/packages/PackageInstaller/res/drawable-watch/action_positive_bg.xml b/packages/PackageInstaller/res/drawable-watch/action_positive_bg.xml deleted file mode 100644 index 3e8590f261caea558e026ec178e02964d15c3b65..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable-watch/action_positive_bg.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<ripple xmlns:android="http://schemas.android.com/apk/res/android" - android:color="?android:colorControlHighlight"> - <item> - <shape android:shape="oval" android:tint="@color/btn_colored_background_material"> - <solid android:color="@android:color/white" /> - <size android:width="40dp" android:height="40dp" /> - </shape> - </item> -</ripple> diff --git a/packages/PackageInstaller/res/drawable-watch/cancel_button.xml b/packages/PackageInstaller/res/drawable-watch/cancel_button.xml deleted file mode 100644 index 8e4d2d48f8a5473c0eb2471ce0f31c2cfcb2df3d..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable-watch/cancel_button.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > - <item android:drawable="@drawable/action_negative_bg" /> - <item android:drawable="@drawable/ic_cc_clear" android:gravity="center" /> -</layer-list> diff --git a/packages/PackageInstaller/res/drawable-watch/confirm_button.xml b/packages/PackageInstaller/res/drawable-watch/confirm_button.xml deleted file mode 100644 index d1bfae331bf55d544251c13b69911c254b72cf7c..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable-watch/confirm_button.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > - <item android:drawable="@drawable/action_positive_bg" /> - <item android:drawable="@drawable/ic_cc_checkmark" android:gravity="center" /> -</layer-list> diff --git a/packages/PackageInstaller/res/drawable-watch/deny_button.xml b/packages/PackageInstaller/res/drawable-watch/deny_button.xml deleted file mode 100644 index 0a2e1ae16931ef54644b9e6f3132de5be1507b11..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable-watch/deny_button.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > - <item android:drawable="@drawable/action_negative_bg" /> - <item android:drawable="@drawable/ic_cc_deny" android:gravity="center" /> -</layer-list> diff --git a/packages/PackageInstaller/res/drawable-watch/ic_cc_checkmark.xml b/packages/PackageInstaller/res/drawable-watch/ic_cc_checkmark.xml deleted file mode 100644 index 832e090fc3848d83ba2e75feb7969b694ad143d8..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable-watch/ic_cc_checkmark.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z" - android:fillColor="#FFFFFF"/> -</vector> diff --git a/packages/PackageInstaller/res/drawable-watch/ic_cc_clear.xml b/packages/PackageInstaller/res/drawable-watch/ic_cc_clear.xml deleted file mode 100644 index 06bb30b3207ea13c2d369e3b5f2a3af1e0298763..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable-watch/ic_cc_clear.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" - android:fillColor="#FFFFFF"/> -</vector> diff --git a/packages/PackageInstaller/res/drawable-watch/ic_cc_deny.xml b/packages/PackageInstaller/res/drawable-watch/ic_cc_deny.xml deleted file mode 100644 index 971dfcc84f3f63295f673d062ad5f381b419b251..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable-watch/ic_cc_deny.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zM4 12c0-4.42 3.58-8 8-8 1.85 0 3.55.63 4.9 1.69L5.69 16.9C4.63 15.55 4 13.85 4 12zm8 8c-1.85 0-3.55-.63-4.9-1.69L18.31 7.1C19.37 8.45 20 10.15 20 12c0 4.42-3.58 8-8 8z" - android:fillColor="#FFFFFF"/> -</vector> diff --git a/packages/PackageInstaller/res/drawable-xhdpi/ic_fail.png b/packages/PackageInstaller/res/drawable-xhdpi/ic_fail.png deleted file mode 100644 index 6deb808c81f9881494e34291f7c9588037a78db6..0000000000000000000000000000000000000000 Binary files a/packages/PackageInstaller/res/drawable-xhdpi/ic_fail.png and /dev/null differ diff --git a/packages/PackageInstaller/res/drawable-xhdpi/ic_success.png b/packages/PackageInstaller/res/drawable-xhdpi/ic_success.png deleted file mode 100644 index 25f8658f5c39e86a4bfe4438dacf7cb2b59a5d71..0000000000000000000000000000000000000000 Binary files a/packages/PackageInstaller/res/drawable-xhdpi/ic_success.png and /dev/null differ diff --git a/packages/PackageInstaller/res/drawable-xhdpi/tab_unselected_holo.9.png b/packages/PackageInstaller/res/drawable-xhdpi/tab_unselected_holo.9.png deleted file mode 100644 index 9465173781eaa7fc9ab0e191904f928ad1c0b8f4..0000000000000000000000000000000000000000 Binary files a/packages/PackageInstaller/res/drawable-xhdpi/tab_unselected_holo.9.png and /dev/null differ diff --git a/packages/PackageInstaller/res/drawable-xxhdpi/tab_unselected_holo.9.png b/packages/PackageInstaller/res/drawable-xxhdpi/tab_unselected_holo.9.png deleted file mode 100644 index 8fcecf76c1997917acacb7a5f4065614a9299512..0000000000000000000000000000000000000000 Binary files a/packages/PackageInstaller/res/drawable-xxhdpi/tab_unselected_holo.9.png and /dev/null differ diff --git a/packages/PackageInstaller/res/drawable/button_ripple_bg.xml b/packages/PackageInstaller/res/drawable/button_ripple_bg.xml deleted file mode 100644 index dabacb10c011179e472b2017f712f5678c3544e1..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable/button_ripple_bg.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2018 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<ripple xmlns:android="http://schemas.android.com/apk/res/android" - android:color="@color/car_card_ripple_background" - android:radius="90dp"> - <item android:id="@android:id/mask" - android:drawable="@drawable/rectangle_ripple_mask" /> -</ripple> diff --git a/packages/PackageInstaller/res/drawable/ic_arrow_back.xml b/packages/PackageInstaller/res/drawable/ic_arrow_back.xml deleted file mode 100644 index 81da87fd1d5d2fd721e0c537a3ca6dad24cdd1f7..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable/ic_arrow_back.xml +++ /dev/null @@ -1,30 +0,0 @@ -<!-- - ~ Copyright (C) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> - -<!-- This Icon is used in as the back icon on ActionBar. ActionBar hard code the icon layout and - ~ does not provide a way to customize it. Here to center the icon in action bar, we make up - ~ the margin by add the extra space in the icon itself --> -<vector - android:height="@dimen/car_primary_icon_size" - android:width="@dimen/car_primary_icon_size" - android:tint="@color/car_accent" - android:viewportHeight="24.0" - android:viewportWidth="24.0" - xmlns:android="http://schemas.android.com/apk/res/android"> - <path - android:fillColor="#FF000000" - android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/> -</vector> diff --git a/packages/PackageInstaller/res/drawable/ic_dialog_alert_material.xml b/packages/PackageInstaller/res/drawable/ic_dialog_alert_material.xml deleted file mode 100644 index b01a6d683c18c7d4182e9928408923e06308419e..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable/ic_dialog_alert_material.xml +++ /dev/null @@ -1,25 +0,0 @@ -<!-- -Copyright (C) 2014 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0" - android:tint="?android:attr/colorControlNormal"> - <path - android:pathData="M1,21l22,0L12,2L1,21zM13,18l-2,0l0,-2l2,0L13,18zM13,14l-2,0l0,-4l2,0L13,14z" - android:fillColor="@android:color/white"/> -</vector> diff --git a/packages/PackageInstaller/res/drawable/ic_fail_material.xml b/packages/PackageInstaller/res/drawable/ic_fail_material.xml deleted file mode 100644 index 9d53fdc0180d9430b742c421317dfde61ba0847b..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable/ic_fail_material.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2014 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_fail" - android:tint="?android:attr/colorControlNormal" /> diff --git a/packages/PackageInstaller/res/drawable/ic_info_outline.xml b/packages/PackageInstaller/res/drawable/ic_info_outline.xml deleted file mode 100644 index 86597586d9e6ba0dbb1a79bc467f966465e180ed..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable/ic_info_outline.xml +++ /dev/null @@ -1,24 +0,0 @@ -<!-- -Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24.0dp" - android:height="24.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="?android:attr/colorAccent" - android:pathData="M11.0,17.0l2.0,0.0l0.0,-6.0l-2.0,0.0l0.0,6.0zm1.0,-15.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zm0.0,18.0c-4.41,0.0 -8.0,-3.59 -8.0,-8.0s3.59,-8.0 8.0,-8.0 8.0,3.59 8.0,8.0 -3.59,8.0 -8.0,8.0zM11.0,9.0l2.0,0.0L13.0,7.0l-2.0,0.0l0.0,2.0z"/> -</vector> diff --git a/packages/PackageInstaller/res/drawable/ic_more_items.xml b/packages/PackageInstaller/res/drawable/ic_more_items.xml deleted file mode 100644 index 5fdcdcef7317d51aef0c0ce6ad810a7e2d0e0e54..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable/ic_more_items.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - - <path - android:fillColor="#000000" - android:pathData="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 -7v2h14V7H7z" /> - <path - android:pathData="M0 0h24v24H0z" /> -</vector> \ No newline at end of file diff --git a/packages/PackageInstaller/res/drawable/ic_perm_device_info.xml b/packages/PackageInstaller/res/drawable/ic_perm_device_info.xml deleted file mode 100644 index ef91c74620ac2d0dbe6b2a1546eb5ef7d930bd82..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable/ic_perm_device_info.xml +++ /dev/null @@ -1,24 +0,0 @@ -<!-- - Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24.0dp" - android:height="24.0dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path - android:fillColor="#FF000000" - android:pathData="M26.0,14.0l-4.0,0.0l0.0,4.0l4.0,0.0l0.0,-4.0zm0.0,8.0l-4.0,0.0l0.0,12.0l4.0,0.0L26.0,22.0zm8.0,-19.98L14.0,2.0c-2.21,0.0 -4.0,1.79 -4.0,4.0l0.0,36.0c0.0,2.21 1.79,4.0 4.0,4.0l20.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L38.0,6.0c0.0,-2.21 -1.79,-3.98 -4.0,-3.98zM34.0,38.0L14.0,38.0L14.0,10.0l20.0,0.0l0.0,28.0z"/> -</vector> diff --git a/packages/PackageInstaller/res/drawable/ic_success_material.xml b/packages/PackageInstaller/res/drawable/ic_success_material.xml deleted file mode 100644 index ebcce3b5532c8755d13a65f5918103bd8894b2d1..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable/ic_success_material.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2014 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_success" - android:tint="?android:attr/colorControlNormal" /> diff --git a/packages/PackageInstaller/res/drawable/ic_toc.xml b/packages/PackageInstaller/res/drawable/ic_toc.xml deleted file mode 100644 index 66c476bef832b7062303e8adcd0434d634303379..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable/ic_toc.xml +++ /dev/null @@ -1,24 +0,0 @@ -<!-- - Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24.0dp" - android:height="24.0dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path - android:fillColor="#FF000000" - android:pathData="M6.0,18.0l28.0,0.0l0.0,-4.0L6.0,14.0l0.0,4.0zm0.0,8.0l28.0,0.0l0.0,-4.0L6.0,22.0l0.0,4.0zm0.0,8.0l28.0,0.0l0.0,-4.0L6.0,30.0l0.0,4.0zm32.0,0.0l4.0,0.0l0.0,-4.0l-4.0,0.0l0.0,4.0zm0.0,-20.0l0.0,4.0l4.0,0.0l0.0,-4.0l-4.0,0.0zm0.0,12.0l4.0,0.0l0.0,-4.0l-4.0,0.0l0.0,4.0z"/> -</vector> diff --git a/packages/PackageInstaller/res/drawable/rectangle_ripple_mask.xml b/packages/PackageInstaller/res/drawable/rectangle_ripple_mask.xml deleted file mode 100644 index 69eaf8bd4e4b22def02414c1588d4c51734dd6a1..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/drawable/rectangle_ripple_mask.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2018 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - <corners android:radius="@dimen/car_radius_1" /> - <solid android:color="@android:color/white" /> -</shape> \ No newline at end of file diff --git a/packages/PackageInstaller/res/layout-television/grant_permissions.xml b/packages/PackageInstaller/res/layout-television/grant_permissions.xml deleted file mode 100644 index 44583bfbeb49386d76145f80ac2b9d07ec2995b1..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout-television/grant_permissions.xml +++ /dev/null @@ -1,91 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:paddingLeft="@dimen/action_dialog_padding_left" - android:paddingRight="@dimen/action_dialog_padding_right" - android:paddingTop="@dimen/action_dialog_padding_top" - android:paddingBottom="@dimen/action_dialog_padding_bottom" - android:background="@color/grant_permissions_background_color"> - - <ImageView - android:id="@+id/permission_icon" - android:tint="@color/grant_permissions_app_color" - android:layout_width="@dimen/grant_permissions_app_icon_size" - android:layout_height="@dimen/grant_permissions_app_icon_size" - android:layout_marginTop="@dimen/grant_permissions_app_icon_margin_top"/> - - <LinearLayout - android:orientation="vertical" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="1" - android:layout_marginLeft="@dimen/action_dialog_content_margin_left" - android:layout_marginRight="@dimen/action_dialog_content_margin_right"> - <TextView - android:id="@+id/current_page_text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/grant_permissions_app_breadcrumb_margin_bottom" - android:textAppearance="@style/GrantPermissions.BreadcrumbText" /> - - <TextView - android:id="@+id/permission_message" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/grant_permissions_app_title_margin_bottom" - android:textAppearance="@style/GrantPermissions.TitleText"/> - - <TextView - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_marginBottom="@dimen/grant_permissions_app_details_margin_bottom" - android:layout_weight="1" - android:text="@string/grant_dialog_how_to_change" - android:textAppearance="@style/GrantPermissions.BodyText" /> - </LinearLayout> - - <LinearLayout - android:orientation="vertical" - android:layout_width="@dimen/action_dialog_actions_width" - android:layout_height="wrap_content" - android:layout_marginLeft="@dimen/action_dialog_actions_margin_left" - android:layout_marginTop="@dimen/action_dialog_actions_margin_top"> - <Button - android:id="@+id/permission_allow_button" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/grant_dialog_button_allow" - style="@style/GrantPermissions.ActionItem" /> - - <Button - android:id="@+id/permission_deny_button" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/grant_dialog_button_deny" - style="@style/GrantPermissions.ActionItem" /> - - <Button - android:id="@+id/permission_deny_dont_ask_again_button" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/grant_dialog_button_deny_dont_ask_again" - style="@style/GrantPermissions.ActionItem" /> - </LinearLayout> - -</LinearLayout> diff --git a/packages/PackageInstaller/res/layout-television/header.xml b/packages/PackageInstaller/res/layout-television/header.xml deleted file mode 100644 index 56e35db7109c70ed1fa246e0ddc9ff2c60fcf2ae..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout-television/header.xml +++ /dev/null @@ -1,47 +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. ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:background="?attr/defaultBrandColor" - android:elevation="@dimen/lb_preference_decor_title_container_elevation" - android:orientation="vertical"> - - <FrameLayout - android:id="@+id/decor_title_container" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:background="?attr/defaultBrandColor" - android:elevation="@dimen/lb_preference_decor_title_container_elevation" - android:transitionGroup="false" - > - <TextView - android:id="@+id/decor_title" - android:layout_width="match_parent" - android:layout_height="@dimen/lb_preference_decor_title_text_height" - android:layout_marginTop="@dimen/lb_preference_decor_title_margin_top" - android:layout_marginStart="@dimen/lb_preference_decor_title_margin_start" - android:layout_marginEnd="@dimen/lb_preference_decor_title_margin_end" - android:fontFamily="sans-serif-condensed" - android:gravity="center_vertical" - android:singleLine="true" - android:textSize="@dimen/lb_preference_decor_title_text_size" - android:textColor="?android:attr/textColorPrimary" - /> - </FrameLayout> - -</LinearLayout> diff --git a/packages/PackageInstaller/res/layout-television/permissions_frame.xml b/packages/PackageInstaller/res/layout-television/permissions_frame.xml deleted file mode 100644 index 1dcda8d4abe61e4394ffb1892d0c79f798210dbe..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout-television/permissions_frame.xml +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2015 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> - -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:filterTouchesWhenObscured="true"> - - <FrameLayout - android:layout_width="@dimen/lb_settings_pane_width" - android:layout_height="match_parent" - android:background="@color/lb_preference_decor_list_background" - android:layout_gravity="end"> - - <FrameLayout - android:id="@+id/prefs_container" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <TextView - android:id="@+id/no_permissions" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:text="@string/no_permissions" - android:gravity="center" - android:textAppearance="@android:style/TextAppearance.Large" - /> - - </FrameLayout> - - </FrameLayout> -</FrameLayout> diff --git a/packages/PackageInstaller/res/layout-watch/accept_deny_dialog.xml b/packages/PackageInstaller/res/layout-watch/accept_deny_dialog.xml deleted file mode 100644 index 1a0509eede2d29d92d7338558ad1ab906b847f5b..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout-watch/accept_deny_dialog.xml +++ /dev/null @@ -1,111 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> -<ScrollView - xmlns:android="http://schemas.android.com/apk/res/android" - android:fillViewport="true" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <LinearLayout - android:id="@android:id/content" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical"> - - <FrameLayout - android:adjustViewBounds="true" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:minHeight="@dimen/diag_preferred_padding"> - <ImageView android:id="@android:id/icon" - android:adjustViewBounds="true" - android:maxHeight="24dp" - android:maxWidth="24dp" - android:layout_marginTop="@dimen/diag_icon_margin_top" - android:layout_marginBottom="8dp" - android:layout_gravity="center_horizontal" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:scaleType="centerInside" - android:visibility="gone" - android:src="@null" /> - </FrameLayout> - - <TextView android:id="@android:id/title" - android:gravity="center" - android:layout_marginBottom="8dp" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingLeft="@dimen/diag_preferred_padding" - android:paddingRight="@dimen/diag_preferred_padding" - android:textAppearance="@android:style/TextAppearance.Material.Title" /> - - <TextView - android:id="@android:id/message" - android:gravity="center" - android:layout_marginBottom="8dp" - android:layout_height="wrap_content" - android:layout_width="match_parent" - android:paddingLeft="@dimen/diag_preferred_padding" - android:paddingRight="@dimen/diag_preferred_padding" - android:textAppearance="@android:style/TextAppearance.Material.Subhead" - android:visibility="gone" /> - - <FrameLayout - android:id="@+id/buttonPanel" - android:layout_weight="1" - android:layout_width="match_parent" - android:layout_height="wrap_content"> - <LinearLayout - android:id="@+id/buttonContainer" - android:orientation="horizontal" - android:gravity="center_horizontal|top" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="bottom" - android:paddingTop="8dp" - android:paddingBottom="@dimen/diag_button_padding_bottom" - android:paddingLeft="@dimen/diag_button_padding_horizontal" - android:paddingRight="@dimen/diag_button_padding_horizontal" - style="?android:attr/buttonBarStyle"> - - <ImageButton - android:id="@android:id/button2" - android:src="@drawable/ic_cc_clear" - android:background="@drawable/accept_deny_dialog_negative_bg" - android:contentDescription="@string/generic_cancel" - android:layout_width="@dimen/diag_button_size" - android:layout_height="@dimen/diag_button_size" - android:visibility="gone" /> - - <Space - android:id="@+id/spacer" - android:layout_width="0dp" - android:layout_height="0dp" - android:visibility="gone" - android:layout_weight="1" /> - - <ImageButton - android:id="@android:id/button1" - android:src="@drawable/ic_cc_checkmark" - android:background="@drawable/accept_deny_dialog_positive_bg" - android:contentDescription="@string/generic_yes" - android:layout_width="@dimen/diag_button_size" - android:layout_height="@dimen/diag_button_size" - android:visibility="gone" /> - </LinearLayout> - </FrameLayout> - </LinearLayout> -</ScrollView> diff --git a/packages/PackageInstaller/res/layout-watch/wear_review_permission_action_pref.xml b/packages/PackageInstaller/res/layout-watch/wear_review_permission_action_pref.xml deleted file mode 100644 index 2b10c4dbb0c667be2183f804a88d97e6c66f9c9e..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout-watch/wear_review_permission_action_pref.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2017 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<TextView - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+android:id/title" - android:gravity="center" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingTop="@dimen/wear_permission_review_pref_padding" - android:paddingBottom="@dimen/wear_permission_review_pref_padding" - android:textAppearance="@android:style/TextAppearance.Material.Title" /> diff --git a/packages/PackageInstaller/res/layout-watch/wear_review_permission_title_pref.xml b/packages/PackageInstaller/res/layout-watch/wear_review_permission_title_pref.xml deleted file mode 100644 index 67928356116f67ae0ad37548f3d7d04f8e535a57..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout-watch/wear_review_permission_title_pref.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2017 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@android:id/content" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingBottom="@dimen/wear_permission_review_pref_padding" - android:orientation="vertical"> - <ImageView android:id="@+android:id/icon" - android:adjustViewBounds="true" - android:maxHeight="@dimen/wear_permission_review_icon_size" - android:maxWidth="@dimen/wear_permission_review_icon_size" - android:layout_gravity="center_horizontal" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:scaleType="centerInside" /> - <TextView android:id="@+android:id/title" - android:gravity="center" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingLeft="@dimen/diag_preferred_padding" - android:paddingRight="@dimen/diag_preferred_padding" - android:textAppearance="@android:style/TextAppearance.Material.Title" /> -</LinearLayout> diff --git a/packages/PackageInstaller/res/layout/car_app_permissions.xml b/packages/PackageInstaller/res/layout/car_app_permissions.xml deleted file mode 100644 index e052b67af81f4f90e303705a958c9ded45531c8d..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout/car_app_permissions.xml +++ /dev/null @@ -1,68 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2018 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical"> - <RelativeLayout - android:layout_width="match_parent" - android:layout_height="@dimen/car_app_bar_height" - android:gravity="end|center_vertical" > - <FrameLayout - android:id="@+id/action_bar_icon_container" - android:layout_width="@dimen/car_margin" - android:layout_height="@dimen/car_app_bar_height" - android:foreground="@drawable/button_ripple_bg" - android:layout_alignParentStart="true"> - <ImageView - android:layout_width="@dimen/car_primary_icon_size" - android:layout_height="@dimen/car_primary_icon_size" - android:tint="@color/car_tint" - android:scaleType="fitCenter" - android:layout_gravity="center" - android:src="@drawable/ic_arrow_back"/> - </FrameLayout> - <TextView - android:id="@+id/title" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginStart="@dimen/car_margin" - android:textAppearance="@style/TextAppearance.Car.Title2" - android:text="@string/app_permissions" - android:layout_gravity="center_vertical" - android:layout_centerVertical="true" - android:layout_alignParentStart="true" - android:maxLines="1" - android:ellipsize="end"/> - </RelativeLayout> - - <View - android:layout_width="match_parent" - android:layout_height="@dimen/car_list_divider_height" - android:background="@color/car_list_divider"/> - - <androidx.car.widget.PagedListView - android:id="@+id/list" - android:layout_width="match_parent" - android:layout_height="match_parent" - app:showPagedListViewDivider="true" - app:alignDividerStartTo="@id/container" - app:gutter="both"/> - -</LinearLayout> diff --git a/packages/PackageInstaller/res/layout/grant_permissions.xml b/packages/PackageInstaller/res/layout/grant_permissions.xml deleted file mode 100644 index f2a041fd0f5f3b1fb0632a826d0c8adb9fb47fb9..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout/grant_permissions.xml +++ /dev/null @@ -1,141 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<!-- Position subsequent dialogs with the button bar at same height --> -<com.android.packageinstaller.permission.ui.ManualLayoutFrame - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:clipChildren="false"> - - <!-- In (hopefully very rare) case dialog is too high: allow scrolling --> - <ScrollView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:clipChildren="false"> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:clipChildren="false"> - - <!-- allow some space around dialog, esp. in landscape --> - <Space - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_weight="10" - android:visibility="invisible" /> - - <!-- The dialog --> - <LinearLayout - android:layout_height="wrap_content" - android:orientation="vertical" - android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.PermissionGrant" - style="@*android:style/PermissionGrantDialog"> - - <FrameLayout - android:id="@+id/content_container" - android:layout_width="match_parent" - android:layout_height="wrap_content"> - - <include layout="@layout/grant_permissions_content" /> - - </FrameLayout> - - <!-- Button row on bottom of dialog --> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:gravity="bottom" - style="?android:attr/buttonBarStyle"> - - <LinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="horizontal"> - - <!-- dummy to enforce height --> - <Button - android:layout_width="0dp" - android:layout_height="wrap_content" - android:visibility="invisible" - style="?android:attr/buttonBarButtonStyle" /> - - <!-- If several dialogs are shown in a row, show e.g. "1/3" --> - <TextView - android:id="@+id/current_page_text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - style="@*android:style/PermissionGrantIndex" /> - - </LinearLayout> - - <com.android.packageinstaller.permission.ui.ButtonBarLayout - android:id="@+id/button_group" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - android:orientation="horizontal" - android:gravity="end"> - - <Button - android:id="@+id/permission_more_info_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/grant_dialog_button_more_info" - android:visibility="gone" - style="?android:attr/buttonBarButtonStyle" /> - - <Space - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_weight="1" - android:visibility="invisible" /> - - <Button - android:id="@+id/permission_deny_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/grant_dialog_button_deny" - style="?android:attr/buttonBarButtonStyle" /> - - <Button - android:id="@+id/permission_allow_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/grant_dialog_button_allow" - style="?android:attr/buttonBarButtonStyle" /> - - </com.android.packageinstaller.permission.ui.ButtonBarLayout> - - </LinearLayout> - - </LinearLayout> - - <!-- allow some space around dialog, esp. in landscape --> - <Space - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_weight="10" - android:visibility="invisible" /> - - </LinearLayout> - - </ScrollView> - -</com.android.packageinstaller.permission.ui.ManualLayoutFrame> diff --git a/packages/PackageInstaller/res/layout/grant_permissions_content.xml b/packages/PackageInstaller/res/layout/grant_permissions_content.xml deleted file mode 100644 index caa1d7665ab593693ac53e047a31031f0d4440e2..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout/grant_permissions_content.xml +++ /dev/null @@ -1,105 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2018 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> - -<!-- Title of dialog --> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.PermissionGrant"> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - style="@*android:style/PermissionGrantDescription"> - - <ImageView - android:id="@+id/permission_icon" - style="@*android:style/PermissionGrantTitleIcon" /> - - <TextView - android:id="@+id/permission_message" - android:layout_width="match_parent" - android:layout_height="wrap_content" - style="?android:attr/titleTextStyle" /> - - </LinearLayout> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - style="@*android:style/PermissionGrantContent" > - - <!-- Option one: Show a radio group of foreground / always / deny --> - <RadioGroup - android:id="@+id/foreground_or_always_radiogroup" - android:animateLayoutChanges="true" - android:layout_width="match_parent" - android:layout_height="wrap_content" - style="@*android:style/PermissionGrantRadioGroup" > - - <RadioButton - android:id="@+id/foreground_only_radio_button" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/allow_permission_foreground_only" - style="@android:attr/radioButtonStyle" /> - - <RadioButton - android:id="@+id/always_radio_button" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/allow_permission_always" - style="@android:attr/radioButtonStyle" /> - - <RadioButton - android:id="@+id/deny_dont_ask_again_radio_button" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/deny_permission_deny_and_dont_ask_again" - style="@android:attr/radioButtonStyle" /> - - </RadioGroup> - - <!-- Option two: Show a detailed message about the change --> - <TextView - android:id="@+id/detail_message" - android:layout_width="match_parent" - android:layout_height="wrap_content" - style="@*android:style/PermissionGrantDetailMessage" /> - - <!-- Shown when detail_message and do_not_ask_checkbox are shown --> - <Space - android:id="@+id/detail_message_do_not_ask_checkbox_space" - android:layout_width="match_parent" - style="@*android:style/PermissionGrantDetailMessageSpace" /> - - <!-- Either with option two or by itself: Show a checkbox allowing to deny with - prejudice --> - <CheckBox - android:id="@+id/do_not_ask_checkbox" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/never_ask_again" - style="@android:attr/checkboxStyle" /> - - </LinearLayout> - -</LinearLayout> diff --git a/packages/PackageInstaller/res/layout/header.xml b/packages/PackageInstaller/res/layout/header.xml deleted file mode 100644 index 45e6972c41289e2105ea2ded7d7d8ec0b397f1eb..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout/header.xml +++ /dev/null @@ -1,54 +0,0 @@ -<!-- - Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<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/colorSecondary" - android:gravity="center_vertical" > - - <ImageView android:id="@+id/icon" - android:layout_width="@dimen/header_subsettings_margin_start" - android:layout_height="40dp" - android:gravity="end" - android:layout_centerVertical="true" /> - - <TextView - android:id="@+id/name" - android:layout_height="wrap_content" - android:layout_width="match_parent" - android:layout_marginStart="@dimen/header_subsettings_margin_start" - android:layout_alignWithParentIfMissing="true" - android:layout_centerVertical="true" - android:textAppearance="?android:attr/textAppearanceMedium" - android:textColor="?android:attr/textColorPrimary" - android:textAlignment="viewStart" /> - - <ImageView - android:id="@+id/info" - android:layout_width="56dp" - android:layout_height="56dp" - android:layout_alignParentEnd="true" - android:layout_marginEnd="@dimen/header_subsettings_margin_end" - android:layout_centerVertical="true" - android:minHeight="0dp" - android:minWidth="0dp" - android:scaleType="center" - android:src="@drawable/ic_info_outline" - android:contentDescription="@string/app_permissions_info_button_label" - style="?android:attr/borderlessButtonStyle" /> - -</RelativeLayout> diff --git a/packages/PackageInstaller/res/layout/label.xml b/packages/PackageInstaller/res/layout/label.xml deleted file mode 100644 index e1a51434c1ed800a4a88a3da4b076e694a865249..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout/label.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<TextView xmlns:android="http://schemas.android.com/apk/res/android" - android:textAppearance="?android:attr/textAppearanceMedium" - android:gravity="center" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:padding="16dp"/> diff --git a/packages/PackageInstaller/res/layout/loading_container.xml b/packages/PackageInstaller/res/layout/loading_container.xml deleted file mode 100644 index 5a165deee583241909de18c6cb0b5c6bed08d687..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout/loading_container.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/loading_container" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" - android:gravity="center"> - - <ProgressBar style="?android:attr/progressBarStyleLarge" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - - <TextView android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceSmall" - android:text="@string/loading" - android:paddingTop="4dip" - android:singleLine="true" /> - -</LinearLayout> diff --git a/packages/PackageInstaller/res/layout/permissions_frame.xml b/packages/PackageInstaller/res/layout/permissions_frame.xml deleted file mode 100644 index 156af57e897a5965f698b09b605b02c39522b43e..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout/permissions_frame.xml +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <FrameLayout - android:id="@+id/prefs_container" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <TextView - android:id="@+id/no_permissions" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:text="@string/no_permissions" - android:gravity="center" - style="?android:attr/textAppearanceLarge"> - </TextView> - - </FrameLayout> - - <include layout="@layout/loading_container" /> - -</FrameLayout> diff --git a/packages/PackageInstaller/res/layout/permissions_list.xml b/packages/PackageInstaller/res/layout/permissions_list.xml deleted file mode 100644 index 5e3ae0f5c23da4eeebe3817017b06c8cf54b5644..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout/permissions_list.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<!-- -This is the structure for the list of all permissions. ---> -<com.android.packageinstaller.CaffeinatedScrollView - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/scrollview" - android:fillViewport="true"> - <LinearLayout - android:id="@+id/permission_list" - android:orientation="vertical" - android:layout_width="match_parent" - android:paddingEnd="4dp" - android:layout_height="wrap_content"> - </LinearLayout> -</com.android.packageinstaller.CaffeinatedScrollView> diff --git a/packages/PackageInstaller/res/layout/preference_category_material.xml b/packages/PackageInstaller/res/layout/preference_category_material.xml deleted file mode 100644 index f62260bc1900b3331dcb353da0c9954ba5abb105..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout/preference_category_material.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<!-- Based on frameworks/base/core/res/res/layout/preference_category_material.xml - but has a ViewGroup at the root to make the support lib happy.--> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical"> - - <TextView - android:id="@android:id/title" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginBottom="16dip" - android:textAppearance="@android:style/TextAppearance.Material.Body2" - android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" - android:textColor="?android:attr/colorAccent" - android:paddingTop="16dip" /> - -</LinearLayout> diff --git a/packages/PackageInstaller/res/layout/preference_permissions.xml b/packages/PackageInstaller/res/layout/preference_permissions.xml deleted file mode 100644 index 2a03067c8a7a057afd9933f9690856074fc33d0c..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout/preference_permissions.xml +++ /dev/null @@ -1,80 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<!-- Based off frameworks/base/core/res/res/layout/preference_material.xml - except that this has the negative margin on the image removed - and has a set icon size (and some padding to realign). --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:minHeight="?android:attr/listPreferredItemHeightSmall" - android:gravity="center_vertical" - android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" - android:background="?android:attr/selectableItemBackground" - android:focusable="true" - android:clipToPadding="false"> - - <LinearLayout - android:id="@android:id/icon_frame" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="start|center_vertical" - android:orientation="horizontal" - android:paddingEnd="20dp" - android:paddingTop="4dp" - android:paddingBottom="4dp"> - <com.android.packageinstaller.permission.ui.PreferenceImageView - android:id="@android:id/icon" - android:layout_width="24dp" - android:layout_height="24dp" - android:scaleType="fitCenter" /> - </LinearLayout> - - <RelativeLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - android:paddingTop="16dp" - android:paddingBottom="16dp"> - - <TextView android:id="@android:id/title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:singleLine="true" - android:textAppearance="?android:attr/textAppearanceListItem" - android:ellipsize="marquee" /> - - <TextView android:id="@android:id/summary" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@android:id/title" - android:layout_alignStart="@android:id/title" - android:textAppearance="?android:attr/textAppearanceListItemSecondary" - android:textColor="?android:attr/textColorSecondary" - android:maxLines="10" /> - - </RelativeLayout> - - <!-- Preference should place its actual preference widget here. --> - <LinearLayout android:id="@android:id/widget_frame" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="end|center_vertical" - android:paddingStart="16dp" - android:orientation="vertical" /> - -</LinearLayout> diff --git a/packages/PackageInstaller/res/layout/preference_permissions_switch.xml b/packages/PackageInstaller/res/layout/preference_permissions_switch.xml deleted file mode 100644 index 50e2c99f3a014ae29f20ae4d9d8adb78ef9bc613..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout/preference_permissions_switch.xml +++ /dev/null @@ -1,80 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<!-- Based off frameworks/base/core/res/res/layout/preference_material.xml - except that this has the negative margin on the image removed - and has a set icon size (and some padding to align). --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:minHeight="?android:attr/listPreferredItemHeightSmall" - android:gravity="center_vertical" - android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" - android:background="?android:attr/selectableItemBackground" - android:focusable="true" - android:clipToPadding="false"> - - <LinearLayout - android:id="@android:id/icon_frame" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="start|center_vertical" - android:orientation="horizontal" - android:paddingEnd="20dp" - android:paddingTop="4dp" - android:paddingBottom="4dp"> - <com.android.packageinstaller.permission.ui.PreferenceImageView - android:id="@android:id/icon" - android:layout_width="36dp" - android:layout_height="36dp" - android:scaleType="fitCenter" /> - </LinearLayout> - - <RelativeLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - android:paddingTop="16dp" - android:paddingBottom="16dp"> - - <TextView android:id="@android:id/title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:singleLine="true" - android:textAppearance="?android:attr/textAppearanceListItem" - android:ellipsize="marquee" /> - - <TextView android:id="@android:id/summary" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@android:id/title" - android:layout_alignStart="@android:id/title" - android:textAppearance="?android:attr/textAppearanceListItemSecondary" - android:textColor="?android:attr/textColorSecondary" - android:maxLines="10" /> - - </RelativeLayout> - - <!-- Preference should place its actual preference widget here. --> - <LinearLayout android:id="@android:id/widget_frame" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="end|center_vertical" - android:paddingStart="16dp" - android:orientation="vertical" /> - -</LinearLayout> diff --git a/packages/PackageInstaller/res/layout/review_permissions.xml b/packages/PackageInstaller/res/layout/review_permissions.xml deleted file mode 100644 index 6a1c6b3ea774db32416a5b2e3cb35f874eb1613d..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/layout/review_permissions.xml +++ /dev/null @@ -1,112 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:layout_marginTop="32dip" - android:layout_marginBottom="8dip" - android:orientation="vertical"> - - <LinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="16dip" - android:layout_marginEnd="16dip" - android:layout_marginBottom="16dip" - android:orientation="horizontal"> - - <ImageView - android:id="@+id/app_icon" - android:layout_width="36dip" - android:layout_height="36dip" - android:scaleType="fitCenter"> - </ImageView> - - <TextView - android:id="@+id/permissions_message" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="16dip" - style="?android:attr/textAppearanceMedium"> - </TextView> - - </LinearLayout> - - <FrameLayout - android:id="@+id/preferences_frame" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:layout_marginStart="2dip" - android:layout_marginEnd="2dip" - android:layout_weight="1"> - </FrameLayout> - - <LinearLayout - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:paddingStart="2dip" - android:paddingTop="16dip"> - - <Button - android:id="@+id/permission_more_info_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="bottom" - android:visibility="gone" - style="?android:attr/buttonBarButtonStyle" - android:text="@string/grant_dialog_button_more_info"> - </Button> - - <Space - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_weight="1" - android:visibility="invisible"> - </Space> - - <com.android.packageinstaller.permission.ui.ButtonBarLayout - android:id="@+id/button_group" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="bottom" - android:orientation="horizontal" - android:gravity="bottom"> - - <Button - android:id="@+id/cancel_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - style="?android:attr/buttonBarButtonStyle" - android:text="@string/review_button_cancel"> - </Button> - - <Button - android:id="@+id/continue_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - style="?android:attr/buttonBarButtonStyle" - android:layout_marginStart="8dip" - android:text="@string/review_button_continue"> - </Button> - - </com.android.packageinstaller.permission.ui.ButtonBarLayout> - - </LinearLayout> - -</LinearLayout> diff --git a/packages/PackageInstaller/res/values-television/colors.xml b/packages/PackageInstaller/res/values-television/colors.xml index 6afe24830790b072bd6f5598e9be743dbcf9fcb5..1cacc002465b7d92802ec58a27867611cb3379a6 100644 --- a/packages/PackageInstaller/res/values-television/colors.xml +++ b/packages/PackageInstaller/res/values-television/colors.xml @@ -24,16 +24,5 @@ <color name="lb_header_banner_color">#1f292d</color> - <color name="grant_permissions_background_color">#ff263238</color> - <color name="grant_permissions_app_color">@color/grant_permissions_white_text_alpha_100</color> - <color name="grant_permissions_progress_color">@color/grant_permissions_white_text_alpha_100</color> - <color name="grant_permissions_title_color">@color/grant_permissions_white_text_alpha_70</color> - <color name="grant_permissions_body_color">@color/grant_permissions_white_text_alpha_70</color> - <color name="grant_permissions_button_color">@color/grant_permissions_white_text_alpha_100</color> - <color name="grant_permissions_focus_highlight">#26eeeeee</color> - - <color name="grant_permissions_white_text_alpha_100">@color/off_white</color> - <color name="grant_permissions_white_text_alpha_70">#b2eeeeee</color> - <color name="off_white">#ffeeeeee</color> </resources> diff --git a/packages/PackageInstaller/res/values-television/dimens.xml b/packages/PackageInstaller/res/values-television/dimens.xml index 03038386e08dff0abf5b0f78980b533508fb23c3..d1c232e693b0d7ec3c844d7a68b12f8c6e21efee 100644 --- a/packages/PackageInstaller/res/values-television/dimens.xml +++ b/packages/PackageInstaller/res/values-television/dimens.xml @@ -15,13 +15,6 @@ --> <resources> - <dimen name="grant_permissions_app_icon_size">64dp</dimen> - <dimen name="grant_permissions_app_icon_margin_top">19dp</dimen> - - <dimen name="grant_permissions_app_breadcrumb_margin_bottom">3dp</dimen> - <dimen name="grant_permissions_app_title_margin_bottom">18dp</dimen> - <dimen name="grant_permissions_app_details_margin_bottom">8dp</dimen> - <dimen name="action_dialog_z">16dp</dimen> <dimen name="action_dialog_padding_left">52dp</dimen> <dimen name="action_dialog_padding_right">40dp</dimen> diff --git a/packages/PackageInstaller/res/values-television/strings.xml b/packages/PackageInstaller/res/values-television/strings.xml deleted file mode 100644 index c11d865cedd853ea8cd76bd7108ac6f835551704..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/values-television/strings.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- Title for the dialog button to deny a permission grant and never ask the user again. --> - <string name="grant_dialog_button_deny_dont_ask_again">Deny and don\'t ask again</string> - - <!-- Instructional text telling the user how to change permission grants later. --> - <string name="grant_dialog_how_to_change">You can change this later in Settings > Apps</string> - - <!-- Template for the current permission from the total number of permissions. --> - <string name="current_permission_template"> - <xliff:g id="current_permission_index" example="1">%1$s</xliff:g> / - <xliff:g id="permission_count" example="2">%2$s</xliff:g></string> - - <!-- Preference row title for showing system apps. --> - <string name="preference_show_system_apps">Show system apps</string> - - <!--decor title displayed as the page title for different TV permission screens--> - <string name="app_permissions_decor_title">App permissions</string> - <string name="manage_permissions_decor_title">App permissions</string> - <string name="permission_apps_decor_title"><xliff:g id="permission" example="Camera">%1$s</xliff:g> permissions</string> - <string name="additional_permissions_decor_title">Additional permissions</string> - <string name="system_apps_decor_title"><xliff:g id="permission" example="Camera">%1$s</xliff:g> permissions</string> -</resources> diff --git a/packages/PackageInstaller/res/values-television/styles.xml b/packages/PackageInstaller/res/values-television/styles.xml deleted file mode 100644 index 5f712f7d134b5c6feb41bb1213e776c24872e6e3..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/values-television/styles.xml +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<resources> - - <style name="PreferenceThemeOverlay.v14.Permissions"> - <item name="preferenceStyle">@style/Preference.Permissions</item> - <item name="preferenceCategoryStyle">@style/Preference.Category.Permissions</item> - <item name="switchPreferenceStyle">@style/Preference.SwitchPreference.Permissions</item> - </style> - - <style name="Preference.Permissions"> - <item name="layout">@layout/preference_permissions</item> - </style> - - <style name="Preference.Category.Permissions"> - <item name="layout">@layout/preference_category_material</item> - </style> - - <style name="Preference.SwitchPreference.Permissions"> - <item name="layout">@layout/preference_permissions_switch</item> - </style> - -</resources> diff --git a/packages/PackageInstaller/res/values-television/themes.xml b/packages/PackageInstaller/res/values-television/themes.xml deleted file mode 100644 index f778fad25ccdfb7d3e801f4c8e7b0bdcb94b7e7b..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/values-television/themes.xml +++ /dev/null @@ -1,71 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2015 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> - -<resources> - <style name="Settings" parent="Theme.Leanback"> - <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Leanback</item> - <item name="android:windowBackground">@android:color/transparent</item> - <item name="android:windowIsTranslucent">true</item> - <item name="android:backgroundDimEnabled">true</item> - <item name="android:backgroundDimAmount">0.8</item> - </style> - - <style name="GrantPermissions" parent="Theme.Leanback"> - <item name="android:windowIsFloating">true</item> - <item name="android:windowAnimationStyle">@style/Animation.Snackbar</item> - <item name="android:windowElevation">@dimen/action_dialog_z</item> - </style> - - <style name="GrantPermissions.BreadcrumbText"> - <item name="android:fontFamily">sans-serif-condensed</item> - <item name="android:textSize">14sp</item> - <item name="android:textColor">@color/grant_permissions_progress_color</item> - </style> - - <style name="GrantPermissions.TitleText"> - <item name="android:fontFamily">sans-serif-light</item> - <item name="android:textSize">24sp</item> - <item name="android:textColor">@color/grant_permissions_title_color</item> - <item name="android:lineSpacingMultiplier">1.221</item> - </style> - - <style name="GrantPermissions.BodyText"> - <item name="android:fontFamily">sans-serif</item> - <item name="android:textSize">14sp</item> - <item name="android:textColor">@color/grant_permissions_body_color</item> - <item name="android:lineSpacingMultiplier">1.465</item> - </style> - - <style name="GrantPermissions.ActionItem"> - <item name="android:gravity">left|center_vertical</item> - <item name="android:fontFamily">sans-serif-condensed</item> - <item name="android:textSize">14sp</item> - <item name="android:textColor">@color/grant_permissions_button_color</item> - <item name="android:lineSpacingMultiplier">1</item> - <item name="android:background">@drawable/grant_permissions_action_item</item> - <item name="android:paddingLeft">@dimen/action_dialog_button_padding_left</item> - <item name="android:paddingRight">@dimen/action_dialog_button_padding_right</item> - <item name="android:paddingTop">@dimen/action_dialog_button_padding_top</item> - <item name="android:paddingBottom">@dimen/action_dialog_button_padding_bottom</item> - <item name="android:minHeight">@dimen/action_dialog_button_min_height</item> - </style> - - <style name="Animation.Snackbar" parent="@android:style/Animation"> - <item name="android:windowEnterAnimation">@anim/snackbar_enter</item> - <item name="android:windowExitAnimation">@anim/snackbar_exit</item> - </style> -</resources> diff --git a/packages/PackageInstaller/res/values-watch/strings.xml b/packages/PackageInstaller/res/values-watch/strings.xml index f940eae6552e3e6a91abd64c61d3541e5ca21c51..25e83893e2a3337e157a4a10386690577cbbd7d3 100644 --- a/packages/PackageInstaller/res/values-watch/strings.xml +++ b/packages/PackageInstaller/res/values-watch/strings.xml @@ -15,21 +15,6 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- Title for the dialog button to deny a permission grant and never ask the user again. [CHAR LIMIT=29]--> - <string name="grant_dialog_button_deny_dont_ask_again">Deny, don\'t ask again</string> - - <!-- Template for the current permission from the total number of permissions. --> - <string name="current_permission_template"> - <xliff:g id="current_permission_index" example="1">%1$s</xliff:g> / - <xliff:g id="permission_count" example="2">%2$s</xliff:g> - </string> - - <!-- Preference row title for showing system apps. --> - <string name="preference_show_system_apps">Show system apps</string> - - <!-- Summary of a permission switch when it's enforced by policy [CHAR LIMIT=17] --> - <string name="permission_summary_enforced_by_policy">Can\'t be changed</string> - <!-- Generic text to indicate a yes. [CHAR LIMIT=10] --> <string name="generic_yes">Yes</string> diff --git a/packages/PackageInstaller/res/values-watch/themes.xml b/packages/PackageInstaller/res/values-watch/themes.xml index 3adcfc546c0098b6ab7ca86b1da1c77e2ceaf7f4..5e52008c7fd699941162b9df8511783e69588113 100644 --- a/packages/PackageInstaller/res/values-watch/themes.xml +++ b/packages/PackageInstaller/res/values-watch/themes.xml @@ -17,10 +17,4 @@ <resources> <style name="DialogWhenLarge" parent="@android:style/Theme.DeviceDefault.NoActionBar"/> - - <style name="Settings" parent="@android:style/Theme.DeviceDefault.NoActionBar" /> - - <style name="GrantPermissions" parent="@android:style/Theme.DeviceDefault.NoActionBar"> - <item name="android:windowBackground">@android:color/transparent</item> - </style> </resources> diff --git a/packages/PackageInstaller/res/values/strings.xml b/packages/PackageInstaller/res/values/strings.xml index 23eb8657e299738e03aa40bbbff46779f1788c9e..6c7160fc2935716184678d72248974542b5d7e17 100644 --- a/packages/PackageInstaller/res/values/strings.xml +++ b/packages/PackageInstaller/res/values/strings.xml @@ -172,204 +172,11 @@ <!-- Dialog attributes to indicate parse errors --> <string name="Parse_error_dlg_text">There was a problem parsing the package.</string> - <!-- Tab label for new permissions being added to an existing app [CHAR LIMIT=20] --> - <string name="newPerms">New</string> - <!-- Tab label for all permissions of an app being installed [CHAR LIMIT=20] --> - <string name="allPerms">All</string> - <!-- Tab label for permissions related to user privacy [CHAR LIMIT=20] --> - <string name="privacyPerms">Privacy</string> - <!-- Tab label for permissions related to device behavior [CHAR LIMIT=20] --> - <string name="devicePerms">Device Access</string> - - <!-- Body text for new tab when there are no new permissions [CHAR LIMIT=NONE] --> - <string name="no_new_perms">This update requires no new permissions.</string> - - <!-- Title for the dialog button to deny a permission grant. [CHAR LIMIT=15] --> - <string name="grant_dialog_button_deny">Deny</string> - - <!-- Title for the dialog button to get more info about a permission. [CHAR LIMIT=15] --> - <string name="grant_dialog_button_more_info">More info</string> - - <!-- Title for the dialog button to deny a permission grant despite a warning of implications. [CHAR LIMIT=15] --> - <string name="grant_dialog_button_deny_anyway">Deny anyway</string> - - <!-- Template for the current permission from the total number of permissions. [CHAR LIMIT=100] --> - <string name="current_permission_template"> - <xliff:g id="current_permission_index" example="1">%1$s</xliff:g> of - <xliff:g id="permission_count" example="2">%2$s</xliff:g></string> - - <!-- Template for the warning message when an app requests a permission. [CHAR LIMIT=100] --> - <string name="permission_warning_template">Allow - <b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> to - <xliff:g id="action" example="do something">%2$s</xliff:g>?</string> - - <!-- Template for the warning message when an app requests the permission to access a - resource even while in the background (i.e. always). [CHAR LIMIT=100] --> - <string name="permission_add_background_warning_template">Always allow - <b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> to - <xliff:g id="action" example="do something">%2$s</xliff:g>?</string> - - <!-- Radio button shown for permissions that can be granted either only while the app is in - foreground or always. If this button is selected the app only gets the permission while in - foreground [CHAR LIMIT=50] --> - <string name="allow_permission_foreground_only">Only while using app</string> - - <!-- Radio button shown for permissions that can be granted either only while the app is in - foreground or always. If this button is selected the app always gets the permission (while in - foreground _and_ while in background) [CHAR LIMIT=50] --> - <string name="allow_permission_always">Always</string> - - <!-- Radio button shown for permissions that can be granted either only while the app is in - foreground or always. If this button is selected the app does not get the permission and the - permissions will always be denied from now on [CHAR LIMIT=50] --> - <string name="deny_permission_deny_and_dont_ask_again">Deny and don\u2019t ask again</string> - - <!-- Template for the message how many permissions are disabled. [CHAR LIMIT=30] --> - <string name="permission_revoked_count"><xliff:g id="count" example="2">%1$d</xliff:g> disabled</string> - - <!-- Message that all permissions are disabled. [CHAR LIMIT=30] --> - <string name="permission_revoked_all">all disabled</string> - - <!-- Message that no permissions are disabled. [CHAR LIMIT=30] --> - <string name="permission_revoked_none">none disabled</string> - - <!-- Permissions --> - - <!-- Title for the dialog button to allow a permission grant. [CHAR LIMIT=15] --> - <string name="grant_dialog_button_allow">Allow</string> - - <!-- Breadcrumb for page of managing application permissions [CHAR LIMIT=50] --> - <string name="app_permissions_breadcrumb">Apps</string> - - <!-- Title for page of managing application permissions [CHAR LIMIT=30] --> - <string name="app_permissions">App permissions</string> - <!-- Checkbox that allows user to not be questioned about this permission - request again [CHAR LIMIT=30] --> - <string name="never_ask_again">Don\'t ask again</string> - - <!-- Label when app requests no permissions [CHAR LIMIT=30] --> - <string name="no_permissions">No permissions</string> - - <!-- Label for button that leads to more permissions [CHAR LIMIT=40] --> - <string name="additional_permissions">Additional permissions</string> - - <!-- Accessibility label for button opening the app-info when clicked [CHAR LIMIT=none] --> - <string name="app_permissions_info_button_label">Open app info</string> - - <!-- Description of how many more permissions to view on next page [CHAR LIMIT=30] --> - <plurals name="additional_permissions_more"> - <item quantity="one"><xliff:g id="count" example="1">%1$d</xliff:g> more</item> - <item quantity="other"><xliff:g id="count" example="2">%1$d</xliff:g> more</item> - </plurals> - - <!-- Warning for turning off permissions on older apps [CHAR LIMIT=none] --> - <string name="old_sdk_deny_warning">This app was designed for an older version of Android. Denying permission may cause it to no longer function as intended.</string> - - <!-- The default description of a permission, i.e. what it does. [CHAR LIMIT=40] --> - <string name="default_permission_description">perform an unknown action</string> - - <!-- Summary of number of apps currently granted a single permission [CHAR LIMIT=45] --> - <string name="app_permissions_group_summary"><xliff:g id="count" example="10">%1$d</xliff:g> of <xliff:g id="count" example="10">%2$d</xliff:g> apps allowed</string> - - <!-- [CHAR LIMIT=NONE] Menu for manage permissions to control whether system apps are shown --> - <string name="menu_show_system">Show system</string> - <!-- [CHAR LIMIT=NONE] Menu for manage permissions to control whether system apps are hidden --> - <string name="menu_hide_system">Hide system</string> - - <!-- [CHAR LIMIT=NONE] Label when no apps requesting this permission --> - <string name="no_apps">No apps</string> - - <!-- [CHAR LIMIT=30] Title of button that leads to location settings --> - <string name="location_settings">Location Settings</string> - - <!-- [CHAR LIMIT=NONE] Warning about how this app cannot have location permission disabled --> - <string name="location_warning"><xliff:g id="app_name" example="Package Installer">%1$s</xliff:g> is a provider of location services for this device. Location access can be modified from location settings.</string> - - <!-- [CHAR LIMIT=NONE] Warning message when turning off permission for system apps --> - <string name="system_warning">If you deny this permission, basic features of your device may no longer function as intended.</string> - - <!-- [CHAR LIMIT=NONE] Summary of a permission switch when it's enforced by policy --> - <string name="permission_summary_enforced_by_policy">Enforced by policy</string> - - <!-- [CHAR LIMIT=60] Summary of a permission switch when the background access is denied by policy --> - <string name="permission_summary_disabled_by_policy_background_only">Background access disabled by policy</string> - - <!-- [CHAR LIMIT=60] Summary of a permission switch when the background access is enabled by policy --> - <string name="permission_summary_enabled_by_policy_background_only">Background access enabled by policy</string> - - <!-- [CHAR LIMIT=60] Summary of a permission switch when the background access is enabled by policy --> - <string name="permission_summary_enabled_by_policy_foreground_only">Foreground access enabled by policy</string> - - <!-- [CHAR LIMIT=60] Summary of a permission switch when it's enforced by an administrator --> - <string name="permission_summary_enforced_by_admin">Controlled by admin</string> - - <string-array name="background_access_chooser_dialog_choices"> - <item>@string/permission_access_always</item> - <item>@string/permission_access_only_foreground</item> - <item>@string/permission_access_never</item> - </string-array> - - <!-- [CHAR LIMIT=30] App can always (when app is in foreground or background) access the resource protected by the permission --> - <string name="permission_access_always">Always</string> - - <!-- [CHAR LIMIT=30] App can only access the resource protected by the permission while app is in foregroud --> - <string name="permission_access_only_foreground">Only while using app</string> - - <!-- [CHAR LIMIT=30] App can never access the resource protected by the permission (Not while app is in foregound and not while app is in background) --> - <string name="permission_access_never">Never</string> - - <!-- Text displayed until loading is done [CHAR LIMIT=50] --> - <string name="loading">Loading\u2026</string> - - <!-- [CHAR LIMIT=45] Title of all permissions settings --> - <string name="all_permissions">All permissions</string> - <!-- [CHAR LIMIT=45] Group of permissions granted to app automatically when installed. --> - <string name="other_permissions">Other app capabilities</string> - - <!-- Title of the permission dialog for accessibility purposes- spoken to the user. [CHAR LIMIT=none] --> - <string name="permission_request_title">Permission request</string> - - <!-- Title for the dialog that warns the user they need to turn off screen overlays - before permissions can be changed. [CHAR LIMIT=NONE] --> - <string name="screen_overlay_title">Screen overlay detected</string> - - <!-- Message for the dialog that warns the user they need to turn off screen overlays - before permissions can be changed. The "Settings > Apps" conveys to the user to - go to Settings and click on apps, this may need updates in RTL languages. [CHAR LIMIT=NONE] --> - <string name="screen_overlay_message">To change this permission setting, you first have to turn off the screen overlay from Settings \u003e Apps</string> - - <!-- Button for the dialog that warns the user they need to turn off screen overlays - before permissions can be changed. [CHAR LIMIT=NONE] --> - <string name="screen_overlay_button">Open settings</string> - <!-- Title of dialog telling users that Install/Uninstall action is not supported on Android Wear. [CHAR LIMIT=30] --> <string name="wear_not_allowed_dlg_title">Android Wear</string> <!-- Title of dialog telling users that Install/Uninstall action is not supported on Android Wear. [CHAR LIMIT=none] --> <string name="wear_not_allowed_dlg_text">Install/Uninstall actions not supported on Wear.</string> - <!-- Review of runtime permissions for legacy apps --> - - <!-- Template for the screen title when app permissions are reviewed on install. [CHAR LIMIT=none] --> - <string name="permission_review_title_template_install">Choose what to allow - <b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> to access</string> - - <!-- Template for the screen title when app permissions are reviewed on update. [CHAR LIMIT=none] --> - <string name="permission_review_title_template_update"> - <b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> has been updated. - Choose what to allow this app to access.</string> - - <!-- Title for the dialog button to cancel the detailed permission review. [CHAR LIMIT=15] --> - <string name="review_button_cancel">Cancel</string> - - <!-- Title for the dialog button to continue accepting the detailed permission review. [CHAR LIMIT=15] --> - <string name="review_button_continue">Continue</string> - - <!-- Title for the category listing the new permissions used by an app. [CHAR LIMIT=30] --> - <string name="new_permissions_category">New permissions</string> - - <!-- Title for the category listing the current permissions used by an app. [CHAR LIMIT=30] --> - <string name="current_permissions_category">Current permissions</string> - <!-- Message that the app to be installed is being staged [CHAR LIMIT=50] --> <string name="message_staging">Staging app…</string> diff --git a/packages/PackageInstaller/res/values/themes.xml b/packages/PackageInstaller/res/values/themes.xml index 3ddb6a7a9444dec873f047359b94e1e25548fb6d..6df6246ff56046d7a2e09f0bc32cb0a6d1ad1d34 100644 --- a/packages/PackageInstaller/res/values/themes.xml +++ b/packages/PackageInstaller/res/values/themes.xml @@ -17,28 +17,6 @@ <resources> - <style name="Settings" - parent="@android:style/Theme.DeviceDefault.Settings"> - </style> - - <style name="CarSettingTheme" parent="Theme.Car.Light.NoActionBar"> - <item name="android:background">@color/car_card</item> - </style> - - <style name="Settings.NoActionBar" parent="@style/Settings"> - <item name="android:windowActionBar">false</item> - <item name="android:windowNoTitle">true</item> - <item name="preferenceTheme">@style/PreferenceThemeOverlay.SettingsBase</item> - </style> - - <style name="GrantPermissions" - parent="@*android:style/Theme.DeviceDefault.Light.Panel.PermissionGrantApp"> - <!-- The following attributes change the behavior of the dialog, hence they should not be - themed --> - <item name="android:windowIsTranslucent">true</item> - <item name="android:windowCloseOnTouchOutside">@*android:bool/config_closeDialogWhenTouchOutside</item> - </style> - <style name="DialogWhenLarge" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar"> <item name="android:textAppearanceMedium">@style/MediumText</item> diff --git a/packages/PackageInstaller/res/xml-watch/watch_permissions.xml b/packages/PackageInstaller/res/xml-watch/watch_permissions.xml deleted file mode 100644 index 8ec8d196fe0019ac1502ceee9292ac32d064a3b0..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/xml-watch/watch_permissions.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> -<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" - android:title="@string/app_permissions" - android:orderingFromXml="true"> - <Preference - android:key="no_permissions" - android:title="@string/no_permissions" /> -</PreferenceScreen> diff --git a/packages/PackageInstaller/res/xml/all_permissions.xml b/packages/PackageInstaller/res/xml/all_permissions.xml deleted file mode 100644 index 5f7f847bafbd773e212438ae89d71578640ffe29..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/res/xml/all_permissions.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" - android:title="@string/all_permissions"> - - <PreferenceCategory - android:key="other_perms" - android:title="@string/other_permissions" /> - -</PreferenceScreen> diff --git a/packages/PackageInstaller/src/android/support/wearable/view/AcceptDenyDialog.java b/packages/PackageInstaller/src/android/support/wearable/view/AcceptDenyDialog.java deleted file mode 100644 index f2129b8f4b1774b6607c81d28d8202defae407f8..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/android/support/wearable/view/AcceptDenyDialog.java +++ /dev/null @@ -1,182 +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 androidx.wear.ble.view; - -import android.annotation.TargetApi; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.graphics.drawable.Drawable; -import android.os.Build; -import androidx.annotation.StyleRes; -import android.view.View; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.Space; -import android.widget.TextView; - -import com.android.packageinstaller.R; - -/** - * A dialog to display a title, a message, and/or an icon with a positive and a negative button. - * - * <p>The buttons are hidden away unless there is a listener attached to the button. Since there's - * no click listener attached by default, the buttons are hidden be default. - */ -@TargetApi(Build.VERSION_CODES.LOLLIPOP) -public class AcceptDenyDialog extends Dialog { - /** Icon at the top of the dialog. */ - protected ImageView mIcon; - /** Title at the top of the dialog. */ - protected TextView mTitle; - /** Message content of the dialog. */ - protected TextView mMessage; - /** Panel containing the buttons. */ - protected View mButtonPanel; - /** Positive button in the button panel. */ - protected ImageButton mPositiveButton; - /** Negative button in the button panel. */ - protected ImageButton mNegativeButton; - /** - * Click listener for the positive button. Positive button should hide if this is <code>null - * </code>. - */ - protected DialogInterface.OnClickListener mPositiveButtonListener; - /** - * Click listener for the negative button. Negative button should hide if this is <code>null - * </code>. - */ - protected DialogInterface.OnClickListener mNegativeButtonListener; - /** Spacer between the positive and negative button. Hidden if one button is hidden. */ - protected View mSpacer; - - private final View.OnClickListener mButtonHandler = (v) -> { - if (v == mPositiveButton && mPositiveButtonListener != null) { - mPositiveButtonListener.onClick(this, DialogInterface.BUTTON_POSITIVE); - dismiss(); - } else if (v == mNegativeButton && mNegativeButtonListener != null) { - mNegativeButtonListener.onClick(this, DialogInterface.BUTTON_NEGATIVE); - dismiss(); - } - }; - - public AcceptDenyDialog(Context context) { - this(context, 0 /* use default context theme */); - } - - public AcceptDenyDialog(Context context, @StyleRes int themeResId) { - super(context, themeResId); - - setContentView(R.layout.accept_deny_dialog); - - mTitle = (TextView) findViewById(android.R.id.title); - mMessage = (TextView) findViewById(android.R.id.message); - mIcon = (ImageView) findViewById(android.R.id.icon); - mPositiveButton = (ImageButton) findViewById(android.R.id.button1); - mPositiveButton.setOnClickListener(mButtonHandler); - mNegativeButton = (ImageButton) findViewById(android.R.id.button2); - mNegativeButton.setOnClickListener(mButtonHandler); - mSpacer = (Space) findViewById(R.id.spacer); - mButtonPanel = findViewById(R.id.buttonPanel); - } - - public ImageButton getButton(int whichButton) { - switch (whichButton) { - case DialogInterface.BUTTON_POSITIVE: - return mPositiveButton; - case DialogInterface.BUTTON_NEGATIVE: - return mNegativeButton; - default: - return null; - } - } - - public void setIcon(Drawable icon) { - mIcon.setVisibility(icon == null ? View.GONE : View.VISIBLE); - mIcon.setImageDrawable(icon); - } - - /** - * @param resId the resourceId of the drawable to use as the icon or 0 if you don't want an icon. - */ - public void setIcon(int resId) { - mIcon.setVisibility(resId == 0 ? View.GONE : View.VISIBLE); - mIcon.setImageResource(resId); - } - - /** @param message the content message text of the dialog. */ - public void setMessage(CharSequence message) { - mMessage.setText(message); - mMessage.setVisibility(message == null ? View.GONE : View.VISIBLE); - } - - /** @param title the title text of the dialog. */ - @Override - public void setTitle(CharSequence title) { - mTitle.setText(title); - } - - /** - * Sets a click listener for a button. - * - * <p>Will hide button bar if all buttons are hidden (i.e. their click listeners are <code>null - * </code>). - * - * @param whichButton {@link DialogInterface.BUTTON_POSITIVE} or {@link - * DialogInterface.BUTTON_NEGATIVE} - * @param listener the listener to set for the button. Hide button if <code>null</code>. - */ - public void setButton(int whichButton, DialogInterface.OnClickListener listener) { - switch (whichButton) { - case DialogInterface.BUTTON_POSITIVE: - mPositiveButtonListener = listener; - break; - case DialogInterface.BUTTON_NEGATIVE: - mNegativeButtonListener = listener; - break; - default: - return; - } - - mSpacer.setVisibility(mPositiveButtonListener == null || mNegativeButtonListener == null - ? View.GONE : View.INVISIBLE); - mPositiveButton.setVisibility( - mPositiveButtonListener == null ? View.GONE : View.VISIBLE); - mNegativeButton.setVisibility( - mNegativeButtonListener == null ? View.GONE : View.VISIBLE); - mButtonPanel.setVisibility( - mPositiveButtonListener == null && mNegativeButtonListener == null - ? View.GONE : View.VISIBLE); - } - - /** - * Convenience method for <code>setButton(DialogInterface.BUTTON_POSITIVE, listener)</code>. - * - * @param listener the listener for the positive button. - */ - public void setPositiveButton(DialogInterface.OnClickListener listener) { - setButton(DialogInterface.BUTTON_POSITIVE, listener); - } - - /** - * Convenience method for <code>setButton(DialogInterface.BUTTON_NEGATIVE, listener)</code>. - * - * @param listener the listener for the positive button. - */ - public void setNegativeButton(DialogInterface.OnClickListener listener) { - setButton(DialogInterface.BUTTON_NEGATIVE, listener); - } -} diff --git a/packages/PackageInstaller/src/android/support/wearable/view/CircledImageView.java b/packages/PackageInstaller/src/android/support/wearable/view/CircledImageView.java deleted file mode 100644 index 0ae344663bf2018cb080f79e292b575122b64af0..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/android/support/wearable/view/CircledImageView.java +++ /dev/null @@ -1,603 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package androidx.wear.ble.view; - -import android.animation.ArgbEvaluator; -import android.animation.ValueAnimator; -import android.animation.ValueAnimator.AnimatorUpdateListener; -import android.annotation.TargetApi; -import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Paint.Style; -import android.graphics.RadialGradient; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Shader; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.util.AttributeSet; -import android.view.View; - -import java.util.Objects; -import com.android.packageinstaller.R; - -import com.android.packageinstaller.R; - -/** - * An image view surrounded by a circle. - */ -@TargetApi(Build.VERSION_CODES.LOLLIPOP) -public class CircledImageView extends View { - - private static final ArgbEvaluator ARGB_EVALUATOR = new ArgbEvaluator(); - - private Drawable mDrawable; - - private final RectF mOval; - private final Paint mPaint; - - private ColorStateList mCircleColor; - - private float mCircleRadius; - private float mCircleRadiusPercent; - - private float mCircleRadiusPressed; - private float mCircleRadiusPressedPercent; - - private float mRadiusInset; - - private int mCircleBorderColor; - - private float mCircleBorderWidth; - private float mProgress = 1f; - private final float mShadowWidth; - - private float mShadowVisibility; - private boolean mCircleHidden = false; - - private float mInitialCircleRadius; - - private boolean mPressed = false; - - private boolean mProgressIndeterminate; - private ProgressDrawable mIndeterminateDrawable; - private Rect mIndeterminateBounds = new Rect(); - private long mColorChangeAnimationDurationMs = 0; - - private float mImageCirclePercentage = 1f; - private float mImageHorizontalOffcenterPercentage = 0f; - private Integer mImageTint; - - private final Drawable.Callback mDrawableCallback = new Drawable.Callback() { - @Override - public void invalidateDrawable(Drawable drawable) { - invalidate(); - } - - @Override - public void scheduleDrawable(Drawable drawable, Runnable runnable, long l) { - // Not needed. - } - - @Override - public void unscheduleDrawable(Drawable drawable, Runnable runnable) { - // Not needed. - } - }; - - private int mCurrentColor; - - private final AnimatorUpdateListener mAnimationListener = new AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - int color = (int) animation.getAnimatedValue(); - if (color != CircledImageView.this.mCurrentColor) { - CircledImageView.this.mCurrentColor = color; - CircledImageView.this.invalidate(); - } - } - }; - - private ValueAnimator mColorAnimator; - - public CircledImageView(Context context) { - this(context, null); - } - - public CircledImageView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public CircledImageView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CircledImageView); - mDrawable = a.getDrawable(R.styleable.CircledImageView_android_src); - - mCircleColor = a.getColorStateList(R.styleable.CircledImageView_circle_color); - if (mCircleColor == null) { - mCircleColor = ColorStateList.valueOf(android.R.color.darker_gray); - } - - mCircleRadius = a.getDimension( - R.styleable.CircledImageView_circle_radius, 0); - mInitialCircleRadius = mCircleRadius; - mCircleRadiusPressed = a.getDimension( - R.styleable.CircledImageView_circle_radius_pressed, mCircleRadius); - mCircleBorderColor = a.getColor( - R.styleable.CircledImageView_circle_border_color, Color.BLACK); - mCircleBorderWidth = a.getDimension(R.styleable.CircledImageView_circle_border_width, 0); - - if (mCircleBorderWidth > 0) { - mRadiusInset += mCircleBorderWidth; - } - - float circlePadding = a.getDimension(R.styleable.CircledImageView_circle_padding, 0); - if (circlePadding > 0) { - mRadiusInset += circlePadding; - } - mShadowWidth = a.getDimension(R.styleable.CircledImageView_shadow_width, 0); - - mImageCirclePercentage = a.getFloat( - R.styleable.CircledImageView_image_circle_percentage, 0f); - - mImageHorizontalOffcenterPercentage = a.getFloat( - R.styleable.CircledImageView_image_horizontal_offcenter_percentage, 0f); - - if (a.hasValue(R.styleable.CircledImageView_image_tint)) { - mImageTint = a.getColor(R.styleable.CircledImageView_image_tint, 0); - } - - mCircleRadiusPercent = a.getFraction(R.styleable.CircledImageView_circle_radius_percent, - 1, 1, 0f); - - mCircleRadiusPressedPercent = a.getFraction( - R.styleable.CircledImageView_circle_radius_pressed_percent, 1, 1, - mCircleRadiusPercent); - - a.recycle(); - - mOval = new RectF(); - mPaint = new Paint(); - mPaint.setAntiAlias(true); - - mIndeterminateDrawable = new ProgressDrawable(); - // {@link #mDrawableCallback} must be retained as a member, as Drawable callback - // is held by weak reference, we must retain it for it to continue to be called. - mIndeterminateDrawable.setCallback(mDrawableCallback); - - setWillNotDraw(false); - - setColorForCurrentState(); - } - - public void setCircleHidden(boolean circleHidden) { - if (circleHidden != mCircleHidden) { - mCircleHidden = circleHidden; - invalidate(); - } - } - - - @Override - protected boolean onSetAlpha(int alpha) { - return true; - } - - @Override - protected void onDraw(Canvas canvas) { - int paddingLeft = getPaddingLeft(); - int paddingTop = getPaddingTop(); - - - float circleRadius = mPressed ? getCircleRadiusPressed() : getCircleRadius(); - if (mShadowWidth > 0 && mShadowVisibility > 0) { - // First let's find the center of the view. - mOval.set(paddingLeft, paddingTop, getWidth() - getPaddingRight(), - getHeight() - getPaddingBottom()); - // Having the center, lets make the shadow start beyond the circled and possibly the - // border. - final float radius = circleRadius + mCircleBorderWidth + - mShadowWidth * mShadowVisibility; - mPaint.setColor(Color.BLACK); - mPaint.setAlpha(Math.round(mPaint.getAlpha() * getAlpha())); - mPaint.setStyle(Style.FILL); - // TODO: precalc and pre-allocate this - mPaint.setShader(new RadialGradient(mOval.centerX(), mOval.centerY(), radius, - new int[]{Color.BLACK, Color.TRANSPARENT}, new float[]{0.6f, 1f}, - Shader.TileMode.MIRROR)); - canvas.drawCircle(mOval.centerX(), mOval.centerY(), radius, mPaint); - mPaint.setShader(null); - } - if (mCircleBorderWidth > 0) { - // First let's find the center of the view. - mOval.set(paddingLeft, paddingTop, getWidth() - getPaddingRight(), - getHeight() - getPaddingBottom()); - // Having the center, lets make the border meet the circle. - mOval.set(mOval.centerX() - circleRadius, mOval.centerY() - circleRadius, - mOval.centerX() + circleRadius, mOval.centerY() + circleRadius); - mPaint.setColor(mCircleBorderColor); - // {@link #Paint.setAlpha} is a helper method that just sets the alpha portion of the - // color. {@link #Paint.setPaint} will clear any previously set alpha value. - mPaint.setAlpha(Math.round(mPaint.getAlpha() * getAlpha())); - mPaint.setStyle(Style.STROKE); - mPaint.setStrokeWidth(mCircleBorderWidth); - - if (mProgressIndeterminate) { - mOval.roundOut(mIndeterminateBounds); - mIndeterminateDrawable.setBounds(mIndeterminateBounds); - mIndeterminateDrawable.setRingColor(mCircleBorderColor); - mIndeterminateDrawable.setRingWidth(mCircleBorderWidth); - mIndeterminateDrawable.draw(canvas); - } else { - canvas.drawArc(mOval, -90, 360 * mProgress, false, mPaint); - } - } - if (!mCircleHidden) { - mOval.set(paddingLeft, paddingTop, getWidth() - getPaddingRight(), - getHeight() - getPaddingBottom()); - // {@link #Paint.setAlpha} is a helper method that just sets the alpha portion of the - // color. {@link #Paint.setPaint} will clear any previously set alpha value. - mPaint.setColor(mCurrentColor); - mPaint.setAlpha(Math.round(mPaint.getAlpha() * getAlpha())); - - mPaint.setStyle(Style.FILL); - float centerX = mOval.centerX(); - float centerY = mOval.centerY(); - - canvas.drawCircle(centerX, centerY, circleRadius, mPaint); - } - - if (mDrawable != null) { - mDrawable.setAlpha(Math.round(getAlpha() * 255)); - - if (mImageTint != null) { - mDrawable.setTint(mImageTint); - } - mDrawable.draw(canvas); - } - - super.onDraw(canvas); - } - - private void setColorForCurrentState() { - int newColor = mCircleColor.getColorForState(getDrawableState(), - mCircleColor.getDefaultColor()); - if (mColorChangeAnimationDurationMs > 0) { - if (mColorAnimator != null) { - mColorAnimator.cancel(); - } else { - mColorAnimator = new ValueAnimator(); - } - mColorAnimator.setIntValues(new int[] { - mCurrentColor, newColor }); - mColorAnimator.setEvaluator(ARGB_EVALUATOR); - mColorAnimator.setDuration(mColorChangeAnimationDurationMs); - mColorAnimator.addUpdateListener(this.mAnimationListener); - mColorAnimator.start(); - } else { - if (newColor != mCurrentColor) { - mCurrentColor = newColor; - invalidate(); - } - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - - final float radius = getCircleRadius() + mCircleBorderWidth + - mShadowWidth * mShadowVisibility; - float desiredWidth = radius * 2; - float desiredHeight = radius * 2; - - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - int width; - int height; - - if (widthMode == MeasureSpec.EXACTLY) { - width = widthSize; - } else if (widthMode == MeasureSpec.AT_MOST) { - width = (int) Math.min(desiredWidth, widthSize); - } else { - width = (int) desiredWidth; - } - - if (heightMode == MeasureSpec.EXACTLY) { - height = heightSize; - } else if (heightMode == MeasureSpec.AT_MOST) { - height = (int) Math.min(desiredHeight, heightSize); - } else { - height = (int) desiredHeight; - } - - super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - if (mDrawable != null) { - // Retrieve the sizes of the drawable and the view. - final int nativeDrawableWidth = mDrawable.getIntrinsicWidth(); - final int nativeDrawableHeight = mDrawable.getIntrinsicHeight(); - final int viewWidth = getMeasuredWidth(); - final int viewHeight = getMeasuredHeight(); - final float imageCirclePercentage = mImageCirclePercentage > 0 - ? mImageCirclePercentage : 1; - - final float scaleFactor = Math.min(1f, - Math.min( - (float) nativeDrawableWidth != 0 - ? imageCirclePercentage * viewWidth / nativeDrawableWidth : 1, - (float) nativeDrawableHeight != 0 - ? imageCirclePercentage - * viewHeight / nativeDrawableHeight : 1)); - - // Scale the drawable down to fit the view, if needed. - final int drawableWidth = Math.round(scaleFactor * nativeDrawableWidth); - final int drawableHeight = Math.round(scaleFactor * nativeDrawableHeight); - - // Center the drawable within the view. - final int drawableLeft = (viewWidth - drawableWidth) / 2 - + Math.round(mImageHorizontalOffcenterPercentage * drawableWidth); - final int drawableTop = (viewHeight - drawableHeight) / 2; - - mDrawable.setBounds(drawableLeft, drawableTop, drawableLeft + drawableWidth, - drawableTop + drawableHeight); - } - - super.onLayout(changed, left, top, right, bottom); - } - - public void setImageDrawable(Drawable drawable) { - if (drawable != mDrawable) { - final Drawable existingDrawable = mDrawable; - mDrawable = drawable; - - final boolean skipLayout = drawable != null - && existingDrawable != null - && existingDrawable.getIntrinsicHeight() == drawable.getIntrinsicHeight() - && existingDrawable.getIntrinsicWidth() == drawable.getIntrinsicWidth(); - - if (skipLayout) { - mDrawable.setBounds(existingDrawable.getBounds()); - } else { - requestLayout(); - } - - invalidate(); - } - } - - public void setImageResource(int resId) { - setImageDrawable(resId == 0 ? null : getContext().getDrawable(resId)); - } - - public void setImageCirclePercentage(float percentage) { - float clamped = Math.max(0, Math.min(1, percentage)); - if (clamped != mImageCirclePercentage) { - mImageCirclePercentage = clamped; - invalidate(); - } - } - - public void setImageHorizontalOffcenterPercentage(float percentage) { - if (percentage != mImageHorizontalOffcenterPercentage) { - mImageHorizontalOffcenterPercentage = percentage; - invalidate(); - } - } - - public void setImageTint(int tint) { - if (tint != mImageTint) { - mImageTint = tint; - invalidate(); - } - } - - public float getCircleRadius() { - float radius = mCircleRadius; - if (mCircleRadius <= 0 && mCircleRadiusPercent > 0) { - radius = Math.max(getMeasuredHeight(), getMeasuredWidth()) * mCircleRadiusPercent; - } - - return radius - mRadiusInset; - } - - public float getCircleRadiusPercent() { - return mCircleRadiusPercent; - } - - public float getCircleRadiusPressed() { - float radius = mCircleRadiusPressed; - - if (mCircleRadiusPressed <= 0 && mCircleRadiusPressedPercent > 0) { - radius = Math.max(getMeasuredHeight(), getMeasuredWidth()) - * mCircleRadiusPressedPercent; - } - - return radius - mRadiusInset; - } - - public float getCircleRadiusPressedPercent() { - return mCircleRadiusPressedPercent; - } - - public void setCircleRadius(float circleRadius) { - if (circleRadius != mCircleRadius) { - mCircleRadius = circleRadius; - invalidate(); - } - } - - /** - * Sets the radius of the circle to be a percentage of the largest dimension of the view. - * @param circleRadiusPercent A {@code float} from 0 to 1 representing the radius percentage. - */ - public void setCircleRadiusPercent(float circleRadiusPercent) { - if (circleRadiusPercent != mCircleRadiusPercent) { - mCircleRadiusPercent = circleRadiusPercent; - invalidate(); - } - } - - public void setCircleRadiusPressed(float circleRadiusPressed) { - if (circleRadiusPressed != mCircleRadiusPressed) { - mCircleRadiusPressed = circleRadiusPressed; - invalidate(); - } - } - - /** - * Sets the radius of the circle to be a percentage of the largest dimension of the view when - * pressed. - * @param circleRadiusPressedPercent A {@code float} from 0 to 1 representing the radius - * percentage. - */ - public void setCircleRadiusPressedPercent(float circleRadiusPressedPercent) { - if (circleRadiusPressedPercent != mCircleRadiusPressedPercent) { - mCircleRadiusPressedPercent = circleRadiusPressedPercent; - invalidate(); - } - } - - @Override - protected void drawableStateChanged() { - super.drawableStateChanged(); - setColorForCurrentState(); - } - - public void setCircleColor(int circleColor) { - setCircleColorStateList(ColorStateList.valueOf(circleColor)); - } - - public void setCircleColorStateList(ColorStateList circleColor) { - if (!Objects.equals(circleColor, mCircleColor)) { - mCircleColor = circleColor; - setColorForCurrentState(); - invalidate(); - } - } - - public ColorStateList getCircleColorStateList() { - return mCircleColor; - } - - public int getDefaultCircleColor() { - return mCircleColor.getDefaultColor(); - } - - /** - * Show the circle border as an indeterminate progress spinner. - * The views circle border width and color must be set for this to have an effect. - * - * @param show true if the progress spinner is shown, false to hide it. - */ - public void showIndeterminateProgress(boolean show) { - mProgressIndeterminate = show; - if (show) { - mIndeterminateDrawable.startAnimation(); - } else { - mIndeterminateDrawable.stopAnimation(); - } - } - - @Override - protected void onVisibilityChanged(View changedView, int visibility) { - super.onVisibilityChanged(changedView, visibility); - if (visibility != View.VISIBLE) { - showIndeterminateProgress(false); - } else if (mProgressIndeterminate) { - showIndeterminateProgress(true); - } - } - - public void setProgress(float progress) { - if (progress != mProgress) { - mProgress = progress; - invalidate(); - } - } - - /** - * Set how much of the shadow should be shown. - * @param shadowVisibility Value between 0 and 1. - */ - public void setShadowVisibility(float shadowVisibility) { - if (shadowVisibility != mShadowVisibility) { - mShadowVisibility = shadowVisibility; - invalidate(); - } - } - - public float getInitialCircleRadius() { - return mInitialCircleRadius; - } - - public void setCircleBorderColor(int circleBorderColor) { - mCircleBorderColor = circleBorderColor; - } - - /** - * Set the border around the circle. - * @param circleBorderWidth Width of the border around the circle. - */ - public void setCircleBorderWidth(float circleBorderWidth) { - if (circleBorderWidth != mCircleBorderWidth) { - mCircleBorderWidth = circleBorderWidth; - invalidate(); - } - } - - @Override - public void setPressed(boolean pressed) { - super.setPressed(pressed); - if (pressed != mPressed) { - mPressed = pressed; - invalidate(); - } - } - - public Drawable getImageDrawable() { - return mDrawable; - } - - /** - * @return the milliseconds duration of the transition animation when the color changes. - */ - public long getColorChangeAnimationDuration() { - return mColorChangeAnimationDurationMs; - } - - /** - * @param mColorChangeAnimationDurationMs the milliseconds duration of the color change - * animation. The color change animation will run if the color changes with {@link #setCircleColor} - * or as a result of the active state changing. - */ - public void setColorChangeAnimationDuration(long mColorChangeAnimationDurationMs) { - this.mColorChangeAnimationDurationMs = mColorChangeAnimationDurationMs; - } -} diff --git a/packages/PackageInstaller/src/android/support/wearable/view/Gusterpolator.java b/packages/PackageInstaller/src/android/support/wearable/view/Gusterpolator.java deleted file mode 100644 index 6b17100fe9a87941e36fcba5a9951cfb2c96d2e1..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/android/support/wearable/view/Gusterpolator.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package androidx.wear.ble.view; - -import android.animation.TimeInterpolator; -import android.annotation.TargetApi; -import android.os.Build; - -/** - * Interpolator that uses a Bezier derived S shaped curve. - * @hide - */ -@TargetApi(Build.VERSION_CODES.KITKAT_WATCH) -class Gusterpolator implements TimeInterpolator { - - /** An instance of {@link androidx.wear.ble.view.Gusterpolator}. */ - public static final Gusterpolator INSTANCE = new Gusterpolator(); - - /** - * To avoid users of this class creating multiple copies needlessly, the constructor is - * private. - */ - private Gusterpolator() {} - - /** - * Lookup table values. - * Generated using a Bezier curve from (0,0) to (1,1) with control points: - * P0 (0,0) - * P1 (0.4, 0) - * P2 (0.2, 1.0) - * P3 (1.0, 1.0) - * - * Values sampled with x at regular intervals between 0 and 1. - */ - private static final float[] VALUES = new float[] { - 0.0f, 0.0002f, 0.0009f, 0.0019f, 0.0036f, 0.0059f, 0.0086f, 0.0119f, 0.0157f, 0.0209f, - 0.0257f, 0.0321f, 0.0392f, 0.0469f, 0.0566f, 0.0656f, 0.0768f, 0.0887f, 0.1033f, 0.1186f, - 0.1349f, 0.1519f, 0.1696f, 0.1928f, 0.2121f, 0.237f, 0.2627f, 0.2892f, 0.3109f, 0.3386f, - 0.3667f, 0.3952f, 0.4241f, 0.4474f, 0.4766f, 0.5f, 0.5234f, 0.5468f, 0.5701f, 0.5933f, - 0.6134f, 0.6333f, 0.6531f, 0.6698f, 0.6891f, 0.7054f, 0.7214f, 0.7346f, 0.7502f, 0.763f, - 0.7756f, 0.7879f, 0.8f, 0.8107f, 0.8212f, 0.8326f, 0.8415f, 0.8503f, 0.8588f, 0.8672f, - 0.8754f, 0.8833f, 0.8911f, 0.8977f, 0.9041f, 0.9113f, 0.9165f, 0.9232f, 0.9281f, 0.9328f, - 0.9382f, 0.9434f, 0.9476f, 0.9518f, 0.9557f, 0.9596f, 0.9632f, 0.9662f, 0.9695f, 0.9722f, - 0.9753f, 0.9777f, 0.9805f, 0.9826f, 0.9847f, 0.9866f, 0.9884f, 0.9901f, 0.9917f, 0.9931f, - 0.9944f, 0.9955f, 0.9964f, 0.9973f, 0.9981f, 0.9986f, 0.9992f, 0.9995f, 0.9998f, 1.0f, 1.0f - }; - - private static final float STEP_SIZE = 1.0f / (VALUES.length - 1); - - @Override - public float getInterpolation(float input) { - if (input >= 1.0f) { - return 1.0f; - } - - if (input <= 0f) { - return 0f; - } - - int position = Math.min( - (int)(input * (VALUES.length - 1)), - VALUES.length - 2); - - float quantized = position * STEP_SIZE; - float difference = input - quantized; - float weight = difference / STEP_SIZE; - - return VALUES[position] + weight * (VALUES[position + 1] - VALUES[position]); - } -} diff --git a/packages/PackageInstaller/src/android/support/wearable/view/ProgressDrawable.java b/packages/PackageInstaller/src/android/support/wearable/view/ProgressDrawable.java deleted file mode 100644 index 51ec8f07f1030a14a67c7236b948e3aa3d970014..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/android/support/wearable/view/ProgressDrawable.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package androidx.wear.ble.view; - -import android.animation.ObjectAnimator; -import android.animation.TimeInterpolator; -import android.animation.ValueAnimator; -import android.annotation.TargetApi; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.Paint; -import android.graphics.PixelFormat; -import android.graphics.RectF; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.util.Property; -import android.view.animation.LinearInterpolator; - -/** - * Drawable for showing an indeterminate progress indicator. - * - * TODO: When Material progress drawable is available in the support library stop using this. - * - * @hide - */ -@TargetApi(Build.VERSION_CODES.KITKAT_WATCH) -class ProgressDrawable extends Drawable { - - private static Property<ProgressDrawable, Integer> LEVEL = - new Property<ProgressDrawable, Integer>(Integer.class, "level") { - @Override - public Integer get(ProgressDrawable drawable) { - return drawable.getLevel(); - } - - @Override - public void set(ProgressDrawable drawable, Integer value) { - drawable.setLevel(value); - drawable.invalidateSelf(); - } - }; - /** Max level for a level drawable, as specified in developer docs for {@link Drawable}. */ - private static final int MAX_LEVEL = 10000; - - /** How many different sections are there, five gives us the material style star. **/ - private static final int NUMBER_OF_SEGMENTS = 5; - - private static final int LEVELS_PER_SEGMENT = MAX_LEVEL / NUMBER_OF_SEGMENTS; - private static final float STARTING_ANGLE = -90f; - private static final long ANIMATION_DURATION = 6000; - private static final int FULL_CIRCLE = 360; - private static final int MAX_SWEEP = 306; - private static final int CORRECTION_ANGLE = FULL_CIRCLE - MAX_SWEEP; - /** How far through each cycle does the bar stop growing and start shrinking, half way. **/ - private static final float GROW_SHRINK_RATIO = 0.5f; - // TODO: replace this with BakedBezierInterpolator when its available in support library. - private static final TimeInterpolator mInterpolator = Gusterpolator.INSTANCE; - - private final RectF mInnerCircleBounds = new RectF(); - private final Paint mPaint = new Paint(); - private final ObjectAnimator mAnimator; - private float mCircleBorderWidth; - private int mCircleBorderColor; - - public ProgressDrawable() { - mPaint.setAntiAlias(true); - mPaint.setStyle(Paint.Style.STROKE); - mAnimator = ObjectAnimator.ofInt(this, LEVEL, 0, MAX_LEVEL); - mAnimator.setRepeatCount(ValueAnimator.INFINITE); - mAnimator.setRepeatMode(ValueAnimator.RESTART); - mAnimator.setDuration(ANIMATION_DURATION); - mAnimator.setInterpolator(new LinearInterpolator()); - } - - public void setRingColor(int color) { - mCircleBorderColor = color; - } - - public void setRingWidth(float width) { - mCircleBorderWidth = width; - } - - public void startAnimation() { - mAnimator.start(); - } - - public void stopAnimation() { - mAnimator.cancel(); - } - - @Override - public void draw(Canvas canvas) { - canvas.save(); - mInnerCircleBounds.set(getBounds()); - mInnerCircleBounds.inset(mCircleBorderWidth / 2.0f, mCircleBorderWidth / 2.0f); - mPaint.setStrokeWidth(mCircleBorderWidth); - mPaint.setColor(mCircleBorderColor); - - float sweepAngle = FULL_CIRCLE; - boolean growing = false; - float correctionAngle = 0; - int level = getLevel(); - - int currentSegment = level / LEVELS_PER_SEGMENT; - int offset = currentSegment * LEVELS_PER_SEGMENT; - float progress = (level - offset) / (float) LEVELS_PER_SEGMENT; - - growing = progress < GROW_SHRINK_RATIO; - correctionAngle = CORRECTION_ANGLE * progress; - - if (growing) { - sweepAngle = MAX_SWEEP * mInterpolator.getInterpolation( - lerpInv(0f, GROW_SHRINK_RATIO, progress)); - } else { - sweepAngle = MAX_SWEEP * (1.0f - mInterpolator.getInterpolation( - lerpInv(GROW_SHRINK_RATIO, 1.0f, progress))); - } - - sweepAngle = Math.max(1, sweepAngle); - - canvas.rotate( - level * (1.0f / MAX_LEVEL) * 2 * FULL_CIRCLE + STARTING_ANGLE + correctionAngle, - mInnerCircleBounds.centerX(), - mInnerCircleBounds.centerY()); - canvas.drawArc(mInnerCircleBounds, - growing ? 0 : MAX_SWEEP - sweepAngle, - sweepAngle, - false, - mPaint); - canvas.restore(); - } - - @Override - public void setAlpha(int i) { - // Not supported. - } - - @Override - public void setColorFilter(ColorFilter colorFilter) { - // Not supported. - } - - @Override - public int getOpacity() { - return PixelFormat.OPAQUE; - } - - @Override - protected boolean onLevelChange(int level) { - return true; // Changing the level of this drawable does change its appearance. - } - - /** - * Returns the interpolation scalar (s) that satisfies the equation: - * {@code value = }lerp(a, b, s) - * - * <p>If {@code a == b}, then this function will return 0. - */ - private static float lerpInv(float a, float b, float value) { - return a != b ? ((value - a) / (b - a)) : 0.0f; - } -} diff --git a/packages/PackageInstaller/src/android/support/wearable/view/SimpleAnimatorListener.java b/packages/PackageInstaller/src/android/support/wearable/view/SimpleAnimatorListener.java deleted file mode 100644 index c8fe58c43f4ed5728c91bffce946c866b888d569..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/android/support/wearable/view/SimpleAnimatorListener.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package androidx.wear.ble.view; - -import android.animation.Animator; -import android.annotation.TargetApi; -import android.os.Build; - -/** - * Convenience class for listening for Animator events that implements the AnimatorListener - * interface and allows extending only methods that are necessary. - */ -@TargetApi(Build.VERSION_CODES.KITKAT_WATCH) -public class SimpleAnimatorListener implements Animator.AnimatorListener { - - private boolean mWasCanceled; - - @Override - public void onAnimationCancel(Animator animator) { - mWasCanceled = true; - } - - @Override - public void onAnimationEnd(Animator animator) { - if (!mWasCanceled) { - onAnimationComplete(animator); - } - } - - @Override - public void onAnimationRepeat(Animator animator) { - } - - @Override - public void onAnimationStart(Animator animator) { - mWasCanceled = false; - } - - /** - * Called when the animation finishes. Not called if the animation was canceled. - */ - public void onAnimationComplete(Animator animator) { - } - - /** - * Provides information if the animation was cancelled. - * @return True if animation was cancelled. - */ - public boolean wasCanceled() { - return mWasCanceled; - } - -} diff --git a/packages/PackageInstaller/src/android/support/wearable/view/WearableDialogHelper.java b/packages/PackageInstaller/src/android/support/wearable/view/WearableDialogHelper.java deleted file mode 100644 index 0151ed573b04b404f550d2e137dc127a88ec276e..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/android/support/wearable/view/WearableDialogHelper.java +++ /dev/null @@ -1,217 +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 androidx.wear.ble.view; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.res.Resources; -import android.graphics.drawable.Drawable; -import androidx.annotation.DrawableRes; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; -import android.util.Log; -import android.widget.Button; - -/** - * Helper to add icons to AlertDialog buttons.AlertDialog buttons. - */ -public class WearableDialogHelper { - private static final String TAG = "WearableDialogHelper"; - - private int mPositiveIconId; - private Drawable mPositiveIcon; - - private int mNeutralIconId; - private Drawable mNeutralIcon; - - private int mNegativeIconId; - private Drawable mNegativeIcon; - - @VisibleForTesting /* package */ Resources mResources; - @VisibleForTesting /* package */ Resources.Theme mTheme; - - /** - * Convenience constructor, equivalent to {@code new WearableDialogHelper(context.getResources(), - * context.getTheme())}. - */ - public WearableDialogHelper(@NonNull Context context) { - this(context.getResources(), context.getTheme()); - } - - /** - * @param resources the Resources used to obtain Drawables from resource IDs. - * @param theme the Theme used to properly obtain Drawables from resource IDs. - */ - public WearableDialogHelper(@NonNull Resources resources, @NonNull Resources.Theme theme) { - mResources = resources; - mTheme = theme; - } - - @Nullable - public Drawable getPositiveIcon() { - return resolveDrawable(mPositiveIcon, mPositiveIconId); - } - - @Nullable - public Drawable getNegativeIcon() { - return resolveDrawable(mNegativeIcon, mNegativeIconId); - } - - @Nullable - public Drawable getNeutralIcon() { - return resolveDrawable(mNeutralIcon, mNeutralIconId); - } - - @NonNull - public WearableDialogHelper setPositiveIcon(@DrawableRes int resId) { - mPositiveIconId = resId; - mPositiveIcon = null; - return this; - } - - @NonNull - public WearableDialogHelper setPositiveIcon(@Nullable Drawable icon) { - mPositiveIcon = icon; - mPositiveIconId = 0; - return this; - } - - @NonNull - public WearableDialogHelper setNegativeIcon(@DrawableRes int resId) { - mNegativeIconId = resId; - mNegativeIcon = null; - return this; - } - - @NonNull - public WearableDialogHelper setNegativeIcon(@Nullable Drawable icon) { - mNegativeIcon = icon; - mNegativeIconId = 0; - return this; - } - - @NonNull - public WearableDialogHelper setNeutralIcon(@DrawableRes int resId) { - mNeutralIconId = resId; - mNeutralIcon = null; - return this; - } - - @NonNull - public WearableDialogHelper setNeutralIcon(@Nullable Drawable icon) { - mNeutralIcon = icon; - mNeutralIconId = 0; - return this; - } - - /** - * Applies the button icons setup in the helper to the buttons in the dialog. - * - * <p>Note that this should be called after {@code AlertDialog.create()}, NOT {@code - * AlertDialog.Builder.create()}. Calling {@code AlertDialog.Builder.show()} would also accomplish - * the same thing. - * - * @param dialog the AlertDialog to style with the helper. - */ - public void apply(@NonNull AlertDialog dialog) { - applyButton(dialog.getButton(DialogInterface.BUTTON_POSITIVE), getPositiveIcon()); - applyButton(dialog.getButton(DialogInterface.BUTTON_NEGATIVE), getNegativeIcon()); - applyButton(dialog.getButton(DialogInterface.BUTTON_NEUTRAL), getNeutralIcon()); - } - - /** Applies the specified drawable to the button. */ - @VisibleForTesting - /* package */ void applyButton(@Nullable Button button, @Nullable Drawable drawable) { - if (button != null) { - button.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null); - button.setAllCaps(false); - } else if (drawable != null) { - Log.w(TAG, "non-null drawable used with missing button, did you call AlertDialog.create()?"); - } - } - - /** Obtain a drawable between a drawable and a resource ID. */ - @VisibleForTesting - /* package */ Drawable resolveDrawable(@Nullable Drawable drawable, @DrawableRes int resId) { - return drawable == null && resId != 0 ? mResources.getDrawable(resId, mTheme) : drawable; - } - - /** Convenience builder to generate an AlertDialog with icons in buttons. */ - public static class DialogBuilder extends AlertDialog.Builder { - private final WearableDialogHelper mHelper; - - public DialogBuilder(Context context) { - super(context); - mHelper = new WearableDialogHelper(context.getResources(), context.getTheme()); - } - - public DialogBuilder(Context context, int themeResId) { - super(context, themeResId); - mHelper = new WearableDialogHelper(context.getResources(), context.getTheme()); - } - - public WearableDialogHelper getHelper() { - return mHelper; - } - - public DialogBuilder setPositiveIcon(@DrawableRes int iconId) { - mHelper.setPositiveIcon(iconId); - return this; - } - - public DialogBuilder setPositiveIcon(@Nullable Drawable icon) { - mHelper.setPositiveIcon(icon); - return this; - } - - public DialogBuilder setNegativeIcon(@DrawableRes int iconId) { - mHelper.setNegativeIcon(iconId); - return this; - } - - public DialogBuilder setNegativeIcon(@Nullable Drawable icon) { - mHelper.setNegativeIcon(icon); - return this; - } - - public DialogBuilder setNeutralIcon(@DrawableRes int iconId) { - mHelper.setNeutralIcon(iconId); - return this; - } - - public DialogBuilder setNeutralIcon(@Nullable Drawable icon) { - mHelper.setNeutralIcon(icon); - return this; - } - - @Override - public AlertDialog create() { - final AlertDialog dialog = super.create(); - dialog.create(); - mHelper.apply(dialog); - return dialog; - } - - @Override - public AlertDialog show() { - final AlertDialog dialog = this.create(); - dialog.show(); - return dialog; - } - } -} diff --git a/packages/PackageInstaller/src/android/support/wearable/view/WearableListView.java b/packages/PackageInstaller/src/android/support/wearable/view/WearableListView.java deleted file mode 100644 index 956ff9e9e6312fad5f6e3f0a6059584c4157aa9e..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/android/support/wearable/view/WearableListView.java +++ /dev/null @@ -1,1387 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package androidx.wear.ble.view; - -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.annotation.TargetApi; -import android.content.Context; -import android.graphics.PointF; -import android.os.Build; -import android.os.Handler; -import androidx.recyclerview.widget.LinearSmoothScroller; -import androidx.recyclerview.widget.RecyclerView; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.util.Log; -import android.util.Property; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.widget.Scroller; - -import java.util.ArrayList; -import java.util.List; - -/** - * An alternative version of ListView that is optimized for ease of use on small screen wearable - * devices. It displays a vertically scrollable list of items, and automatically snaps to the - * nearest item when the user stops scrolling. - * - * <p> - * For a quick start, you will need to implement a subclass of {@link .Adapter}, - * which will create and bind your views to the {@link .ViewHolder} objects. If you want to add - * more visual treatment to your views when they become the central items of the - * WearableListView, have them implement the {@link .OnCenterProximityListener} interface. - * </p> - */ -@TargetApi(Build.VERSION_CODES.KITKAT_WATCH) -public class WearableListView extends RecyclerView { - @SuppressWarnings("unused") - private static final String TAG = "WearableListView"; - - private static final long FLIP_ANIMATION_DURATION_MS = 150; - private static final long CENTERING_ANIMATION_DURATION_MS = 150; - - private static final float TOP_TAP_REGION_PERCENTAGE = .33f; - private static final float BOTTOM_TAP_REGION_PERCENTAGE = .33f; - - // Each item will occupy one third of the height. - private static final int THIRD = 3; - - private final int mMinFlingVelocity; - private final int mMaxFlingVelocity; - - private boolean mMaximizeSingleItem; - private boolean mCanClick = true; - // WristGesture navigation signals are delivered as KeyEvents. Allow developer to disable them - // for this specific View. It might be cleaner to simply have users re-implement onKeyDown(). - // TOOD: Finalize the disabling mechanism here. - private boolean mGestureNavigationEnabled = true; - private int mTapPositionX; - private int mTapPositionY; - private ClickListener mClickListener; - - private Animator mScrollAnimator; - // This is a little hacky due to the fact that animator provides incremental values instead of - // deltas and scrolling code requires deltas. We animate WearableListView directly and use this - // field to calculate deltas. Obviously this means that only one scrolling algorithm can run at - // a time, but I don't think it would be wise to have more than one running. - private int mLastScrollChange; - - private SetScrollVerticallyProperty mSetScrollVerticallyProperty = - new SetScrollVerticallyProperty(); - - private final List<OnScrollListener> mOnScrollListeners = new ArrayList<OnScrollListener>(); - - private final List<OnCentralPositionChangedListener> mOnCentralPositionChangedListeners = - new ArrayList<OnCentralPositionChangedListener>(); - - private OnOverScrollListener mOverScrollListener; - - private boolean mGreedyTouchMode; - - private float mStartX; - - private float mStartY; - - private float mStartFirstTop; - - private final int mTouchSlop; - - private boolean mPossibleVerticalSwipe; - - private int mInitialOffset = 0; - - private Scroller mScroller; - - // Top and bottom boundaries for tap checking. Need to recompute by calling computeTapRegions - // before referencing. - private final float[] mTapRegions = new float[2]; - - private boolean mGestureDirectionLocked; - private int mPreviousCentral = 0; - - // Temp variable for storing locations on screen. - private final int[] mLocation = new int[2]; - - // TODO: Consider clearing this when underlying data set changes. If the data set changes, you - // can't safely assume that this pressed view is in the same place as it was before and it will - // receive setPressed(false) unnecessarily. In theory it should be fine, but in practice we - // have places like this: mIconView.setCircleColor(pressed ? mPressedColor : mSelectedColor); - // This might set selected color on non selected item. Our logic should be: if you change - // underlying data set, all best are off and you need to preserve the state; we will clear - // this field. However, I am not willing to introduce this so late in C development. - private View mPressedView = null; - - private final Runnable mPressedRunnable = new Runnable() { - @Override - public void run() { - if (getChildCount() > 0) { - mPressedView = getChildAt(findCenterViewIndex()); - mPressedView.setPressed(true); - } else { - Log.w(TAG, "mPressedRunnable: the children were removed, skipping."); - } - } - }; - - private final Runnable mReleasedRunnable = new Runnable() { - @Override - public void run() { - releasePressedItem(); - } - }; - - private Runnable mNotifyChildrenPostLayoutRunnable = new Runnable() { - @Override - public void run() { - notifyChildrenAboutProximity(false); - } - }; - - private final AdapterDataObserver mObserver = new AdapterDataObserver() { - @Override - public void onChanged() { - WearableListView.this.addOnLayoutChangeListener(new OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, - int oldLeft, int oldTop, int oldRight, int oldBottom) { - WearableListView.this.removeOnLayoutChangeListener(this); - if (WearableListView.this.getChildCount() > 0) { - WearableListView.this.animateToCenter(); - } - } - }); - } - }; - - public WearableListView(Context context) { - this(context, null); - } - - public WearableListView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public WearableListView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - setHasFixedSize(true); - setOverScrollMode(View.OVER_SCROLL_NEVER); - setLayoutManager(new LayoutManager()); - - final RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() { - @Override - public void onScrollStateChanged(RecyclerView recyclerView, int newState) { - if (newState == RecyclerView.SCROLL_STATE_IDLE && getChildCount() > 0) { - handleTouchUp(null, newState); - } - for (OnScrollListener listener : mOnScrollListeners) { - listener.onScrollStateChanged(newState); - } - } - - @Override - public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - onScroll(dy); - } - }; - setOnScrollListener(onScrollListener); - - final ViewConfiguration vc = ViewConfiguration.get(context); - mTouchSlop = vc.getScaledTouchSlop(); - - mMinFlingVelocity = vc.getScaledMinimumFlingVelocity(); - mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); - } - - @Override - public void setAdapter(RecyclerView.Adapter adapter) { - RecyclerView.Adapter currentAdapter = getAdapter(); - if (currentAdapter != null) { - currentAdapter.unregisterAdapterDataObserver(mObserver); - } - - super.setAdapter(adapter); - - if (adapter != null) { - adapter.registerAdapterDataObserver(mObserver); - } - } - - /** - * @return the position of the center child's baseline; -1 if no center child exists or if - * the center child does not return a valid baseline. - */ - @Override - public int getBaseline() { - // No children implies there is no center child for which a baseline can be computed. - if (getChildCount() == 0) { - return super.getBaseline(); - } - - // Compute the baseline of the center child. - final int centerChildIndex = findCenterViewIndex(); - final int centerChildBaseline = getChildAt(centerChildIndex).getBaseline(); - - // If the center child has no baseline, neither does this list view. - if (centerChildBaseline == -1) { - return super.getBaseline(); - } - - return getCentralViewTop() + centerChildBaseline; - } - - /** - * @return true if the list is scrolled all the way to the top. - */ - public boolean isAtTop() { - if (getChildCount() == 0) { - return true; - } - - int centerChildIndex = findCenterViewIndex(); - View centerView = getChildAt(centerChildIndex); - return getChildAdapterPosition(centerView) == 0 && - getScrollState() == RecyclerView.SCROLL_STATE_IDLE; - } - - /** - * Clears the state of the layout manager that positions list items. - */ - public void resetLayoutManager() { - setLayoutManager(new LayoutManager()); - } - - /** - * Controls whether WearableListView should intercept all touch events and also prevent the - * parent from receiving them. - * @param greedy If true it will intercept all touch events. - */ - public void setGreedyTouchMode(boolean greedy) { - mGreedyTouchMode = greedy; - } - - /** - * By default the first element of the list is initially positioned in the center of the screen. - * This method allows the developer to specify a different offset, e.g. to hide the - * WearableListView before the user is allowed to use it. - * - * @param top How far the elements should be pushed down. - */ - public void setInitialOffset(int top) { - mInitialOffset = top; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent event) { - if (!isEnabled()) { - return false; - } - - if (mGreedyTouchMode && getChildCount() > 0) { - int action = event.getActionMasked(); - if (action == MotionEvent.ACTION_DOWN) { - mStartX = event.getX(); - mStartY = event.getY(); - mStartFirstTop = getChildCount() > 0 ? getChildAt(0).getTop() : 0; - mPossibleVerticalSwipe = true; - mGestureDirectionLocked = false; - } else if (action == MotionEvent.ACTION_MOVE && mPossibleVerticalSwipe) { - handlePossibleVerticalSwipe(event); - } - getParent().requestDisallowInterceptTouchEvent(mPossibleVerticalSwipe); - } - return super.onInterceptTouchEvent(event); - } - - private boolean handlePossibleVerticalSwipe(MotionEvent event) { - if (mGestureDirectionLocked) { - return mPossibleVerticalSwipe; - } - float deltaX = Math.abs(mStartX - event.getX()); - float deltaY = Math.abs(mStartY - event.getY()); - float distance = (deltaX * deltaX) + (deltaY * deltaY); - // Verify that the distance moved in the combined x/y direction is at - // least touch slop before determining the gesture direction. - if (distance > (mTouchSlop * mTouchSlop)) { - if (deltaX > deltaY) { - mPossibleVerticalSwipe = false; - } - mGestureDirectionLocked = true; - } - return mPossibleVerticalSwipe; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (!isEnabled()) { - return false; - } - - // super.onTouchEvent can change the state of the scroll, keep a copy so that handleTouchUp - // can exit early if scrollState != IDLE when the touch event started. - int scrollState = getScrollState(); - boolean result = super.onTouchEvent(event); - if (getChildCount() > 0) { - int action = event.getActionMasked(); - if (action == MotionEvent.ACTION_DOWN) { - handleTouchDown(event); - } else if (action == MotionEvent.ACTION_UP) { - handleTouchUp(event, scrollState); - getParent().requestDisallowInterceptTouchEvent(false); - } else if (action == MotionEvent.ACTION_MOVE) { - if (Math.abs(mTapPositionX - (int) event.getX()) >= mTouchSlop || - Math.abs(mTapPositionY - (int) event.getY()) >= mTouchSlop) { - releasePressedItem(); - mCanClick = false; - } - result |= handlePossibleVerticalSwipe(event); - getParent().requestDisallowInterceptTouchEvent(mPossibleVerticalSwipe); - } else if (action == MotionEvent.ACTION_CANCEL) { - getParent().requestDisallowInterceptTouchEvent(false); - mCanClick = true; - } - } - return result; - } - - private void releasePressedItem() { - if (mPressedView != null) { - mPressedView.setPressed(false); - mPressedView = null; - } - Handler handler = getHandler(); - if (handler != null) { - handler.removeCallbacks(mPressedRunnable); - } - } - - private void onScroll(int dy) { - for (OnScrollListener listener : mOnScrollListeners) { - listener.onScroll(dy); - } - notifyChildrenAboutProximity(true); - } - - /** - * Adds a listener that will be called when the content of the list view is scrolled. - */ - public void addOnScrollListener(OnScrollListener listener) { - mOnScrollListeners.add(listener); - } - - /** - * Removes listener for scroll events. - */ - public void removeOnScrollListener(OnScrollListener listener) { - mOnScrollListeners.remove(listener); - } - - /** - * Adds a listener that will be called when the central item of the list changes. - */ - public void addOnCentralPositionChangedListener(OnCentralPositionChangedListener listener) { - mOnCentralPositionChangedListeners.add(listener); - } - - /** - * Removes a listener that would be called when the central item of the list changes. - */ - public void removeOnCentralPositionChangedListener(OnCentralPositionChangedListener listener) { - mOnCentralPositionChangedListeners.remove(listener); - } - - /** - * Determines if navigation of list with wrist gestures is enabled. - */ - public boolean isGestureNavigationEnabled() { - return mGestureNavigationEnabled; - } - - /** - * Sets whether navigation of list with wrist gestures is enabled. - */ - public void setEnableGestureNavigation(boolean enabled) { - mGestureNavigationEnabled = enabled; - } - - @Override /* KeyEvent.Callback */ - public boolean onKeyDown(int keyCode, KeyEvent event) { - // Respond to keycodes (at least originally generated and injected by wrist gestures). - if (mGestureNavigationEnabled) { - switch (keyCode) { - case KeyEvent.KEYCODE_NAVIGATE_PREVIOUS: - fling(0, -mMinFlingVelocity); - return true; - case KeyEvent.KEYCODE_NAVIGATE_NEXT: - fling(0, mMinFlingVelocity); - return true; - case KeyEvent.KEYCODE_NAVIGATE_IN: - return tapCenterView(); - case KeyEvent.KEYCODE_NAVIGATE_OUT: - // Returing false leaves the action to the container of this WearableListView - // (e.g. finishing the activity containing this WearableListView). - return false; - } - } - return super.onKeyDown(keyCode, event); - } - - /** - * Simulate tapping the child view at the center of this list. - */ - private boolean tapCenterView() { - if (!isEnabled() || getVisibility() != View.VISIBLE) { - return false; - } - int index = findCenterViewIndex(); - View view = getChildAt(index); - ViewHolder holder = getChildViewHolder(view); - if (mClickListener != null) { - mClickListener.onClick(holder); - return true; - } - return false; - } - - private boolean checkForTap(MotionEvent event) { - // No taps are accepted if this view is disabled. - if (!isEnabled()) { - return false; - } - - float rawY = event.getRawY(); - int index = findCenterViewIndex(); - View view = getChildAt(index); - ViewHolder holder = getChildViewHolder(view); - computeTapRegions(mTapRegions); - if (rawY > mTapRegions[0] && rawY < mTapRegions[1]) { - if (mClickListener != null) { - mClickListener.onClick(holder); - } - return true; - } - if (index > 0 && rawY <= mTapRegions[0]) { - animateToMiddle(index - 1, index); - return true; - } - if (index < getChildCount() - 1 && rawY >= mTapRegions[1]) { - animateToMiddle(index + 1, index); - return true; - } - if (index == 0 && rawY <= mTapRegions[0] && mClickListener != null) { - // Special case: if the top third of the screen is empty and the touch event happens - // there, we don't want to immediately disallow the parent from using it. We tell - // parent to disallow intercept only after we locked a gesture. Before that he - // might do something with the action. - mClickListener.onTopEmptyRegionClick(); - return true; - } - return false; - } - - private void animateToMiddle(int newCenterIndex, int oldCenterIndex) { - if (newCenterIndex == oldCenterIndex) { - throw new IllegalArgumentException( - "newCenterIndex must be different from oldCenterIndex"); - } - List<Animator> animators = new ArrayList<Animator>(); - View child = getChildAt(newCenterIndex); - int scrollToMiddle = getCentralViewTop() - child.getTop(); - startScrollAnimation(animators, scrollToMiddle, FLIP_ANIMATION_DURATION_MS); - } - - private void startScrollAnimation(List<Animator> animators, int scroll, long duration) { - startScrollAnimation(animators, scroll, duration, 0); - } - - private void startScrollAnimation(List<Animator> animators, int scroll, long duration, - long delay) { - startScrollAnimation(animators, scroll, duration, delay, null); - } - - private void startScrollAnimation( - int scroll, long duration, long delay, Animator.AnimatorListener listener) { - startScrollAnimation(null, scroll, duration, delay, listener); - } - - private void startScrollAnimation(List<Animator> animators, int scroll, long duration, - long delay, Animator.AnimatorListener listener) { - if (mScrollAnimator != null) { - mScrollAnimator.cancel(); - } - - mLastScrollChange = 0; - ObjectAnimator scrollAnimator = ObjectAnimator.ofInt(this, mSetScrollVerticallyProperty, - 0, -scroll); - - if (animators != null) { - animators.add(scrollAnimator); - AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether(animators); - mScrollAnimator = animatorSet; - } else { - mScrollAnimator = scrollAnimator; - } - mScrollAnimator.setDuration(duration); - if (listener != null) { - mScrollAnimator.addListener(listener); - } - if (delay > 0) { - mScrollAnimator.setStartDelay(delay); - } - mScrollAnimator.start(); - } - - @Override - public boolean fling(int velocityX, int velocityY) { - if (getChildCount() == 0) { - return false; - } - // If we are flinging towards empty space (before first element or after last), we reuse - // original flinging mechanism. - final int index = findCenterViewIndex(); - final View child = getChildAt(index); - int currentPosition = getChildPosition(child); - if ((currentPosition == 0 && velocityY < 0) || - (currentPosition == getAdapter().getItemCount() - 1 && velocityY > 0)) { - return super.fling(velocityX, velocityY); - } - - if (Math.abs(velocityY) < mMinFlingVelocity) { - return false; - } - velocityY = Math.max(Math.min(velocityY, mMaxFlingVelocity), -mMaxFlingVelocity); - - if (mScroller == null) { - mScroller = new Scroller(getContext(), null, true); - } - mScroller.fling(0, 0, 0, velocityY, Integer.MIN_VALUE, Integer.MAX_VALUE, - Integer.MIN_VALUE, Integer.MAX_VALUE); - int finalY = mScroller.getFinalY(); - int delta = finalY / (getPaddingTop() + getAdjustedHeight() / 2); - if (delta == 0) { - // If the fling would not be enough to change position, we increase it to satisfy user's - // intent of switching current position. - delta = velocityY > 0 ? 1 : -1; - } - int finalPosition = Math.max( - 0, Math.min(getAdapter().getItemCount() - 1, currentPosition + delta)); - smoothScrollToPosition(finalPosition); - return true; - } - - public void smoothScrollToPosition(int position, RecyclerView.SmoothScroller smoothScroller) { - LayoutManager layoutManager = (LayoutManager) getLayoutManager(); - layoutManager.setCustomSmoothScroller(smoothScroller); - smoothScrollToPosition(position); - layoutManager.clearCustomSmoothScroller(); - } - - @Override - public ViewHolder getChildViewHolder(View child) { - return (ViewHolder) super.getChildViewHolder(child); - } - - /** - * Adds a listener that will be called when the user taps on the WearableListView or its items. - */ - public void setClickListener(ClickListener clickListener) { - mClickListener = clickListener; - } - - /** - * Adds a listener that will be called when the user drags the top element below its allowed - * bottom position. - * - * @hide - */ - public void setOverScrollListener(OnOverScrollListener listener) { - mOverScrollListener = listener; - } - - private int findCenterViewIndex() { - // TODO(gruszczy): This could be easily optimized, so that we stop looking when we the - // distance starts growing again, instead of finding the closest. It would safe half of - // the loop. - int count = getChildCount(); - int index = -1; - int closest = Integer.MAX_VALUE; - int centerY = getCenterYPos(this); - for (int i = 0; i < count; ++i) { - final View child = getChildAt(i); - int childCenterY = getTop() + getCenterYPos(child); - final int distance = Math.abs(centerY - childCenterY); - if (distance < closest) { - closest = distance; - index = i; - } - } - if (index == -1) { - throw new IllegalStateException("Can't find central view."); - } - return index; - } - - private static int getCenterYPos(View v) { - return v.getTop() + v.getPaddingTop() + getAdjustedHeight(v) / 2; - } - - private void handleTouchUp(MotionEvent event, int scrollState) { - if (mCanClick && event != null && checkForTap(event)) { - Handler handler = getHandler(); - if (handler != null) { - handler.postDelayed(mReleasedRunnable, ViewConfiguration.getTapTimeout()); - } - return; - } - - if (scrollState != RecyclerView.SCROLL_STATE_IDLE) { - // We are flinging, so let's not start animations just yet. Instead we will start them - // when the fling finishes. - return; - } - - if (isOverScrolling()) { - mOverScrollListener.onOverScroll(); - } else { - animateToCenter(); - } - } - - private boolean isOverScrolling() { - return getChildCount() > 0 - // If first view top was below the central top, it means it was never centered. - // Don't allow overscroll, otherwise a simple touch (instead of a drag) will be - // enough to trigger overscroll. - && mStartFirstTop <= getCentralViewTop() - && getChildAt(0).getTop() >= getTopViewMaxTop() - && mOverScrollListener != null; - } - - private int getTopViewMaxTop() { - return getHeight() / 2; - } - - private int getItemHeight() { - // Round up so that the screen is fully occupied by 3 items. - return getAdjustedHeight() / THIRD + 1; - } - - /** - * Returns top of the central {@code View} in the list when such view is fully centered. - * - * This is a more or a less a static value that you can use to align other views with the - * central one. - */ - public int getCentralViewTop() { - return getPaddingTop() + getItemHeight(); - } - - /** - * Automatically starts an animation that snaps the list to center on the element closest to the - * middle. - */ - public void animateToCenter() { - final int index = findCenterViewIndex(); - final View child = getChildAt(index); - final int scrollToMiddle = getCentralViewTop() - child.getTop(); - startScrollAnimation(scrollToMiddle, CENTERING_ANIMATION_DURATION_MS, 0, - new SimpleAnimatorListener() { - @Override - public void onAnimationEnd(Animator animator) { - if (!wasCanceled()) { - mCanClick = true; - } - } - }); - } - - /** - * Animate the list so that the first view is back to its initial position. - * @param endAction Action to execute when the animation is done. - * @hide - */ - public void animateToInitialPosition(final Runnable endAction) { - final View child = getChildAt(0); - final int scrollToMiddle = getCentralViewTop() + mInitialOffset - child.getTop(); - startScrollAnimation(scrollToMiddle, CENTERING_ANIMATION_DURATION_MS, 0, - new SimpleAnimatorListener() { - @Override - public void onAnimationEnd(Animator animator) { - if (endAction != null) { - endAction.run(); - } - } - }); - } - - private void handleTouchDown(MotionEvent event) { - if (mCanClick) { - mTapPositionX = (int) event.getX(); - mTapPositionY = (int) event.getY(); - float rawY = event.getRawY(); - computeTapRegions(mTapRegions); - if (rawY > mTapRegions[0] && rawY < mTapRegions[1]) { - View view = getChildAt(findCenterViewIndex()); - if (view instanceof OnCenterProximityListener) { - Handler handler = getHandler(); - if (handler != null) { - handler.removeCallbacks(mReleasedRunnable); - handler.postDelayed(mPressedRunnable, ViewConfiguration.getTapTimeout()); - } - } - } - } - } - - private void setScrollVertically(int scroll) { - scrollBy(0, scroll - mLastScrollChange); - mLastScrollChange = scroll; - } - - private int getAdjustedHeight() { - return getAdjustedHeight(this); - } - - private static int getAdjustedHeight(View v) { - return v.getHeight() - v.getPaddingBottom() - v.getPaddingTop(); - } - - private void computeTapRegions(float[] tapRegions) { - mLocation[0] = mLocation[1] = 0; - getLocationOnScreen(mLocation); - int mScreenTop = mLocation[1]; - int height = getHeight(); - tapRegions[0] = mScreenTop + height * TOP_TAP_REGION_PERCENTAGE; - tapRegions[1] = mScreenTop + height * (1 - BOTTOM_TAP_REGION_PERCENTAGE); - } - - /** - * Determines if, when there is only one item in the WearableListView, that the single item - * is laid out so that it's height fills the entire WearableListView. - */ - public boolean getMaximizeSingleItem() { - return mMaximizeSingleItem; - } - - /** - * When set to true, if there is only one item in the WearableListView, it will fill the entire - * WearableListView. When set to false, the default behavior will be used and the single item - * will fill only a third of the screen. - */ - public void setMaximizeSingleItem(boolean maximizeSingleItem) { - mMaximizeSingleItem = maximizeSingleItem; - } - - private void notifyChildrenAboutProximity(boolean animate) { - LayoutManager layoutManager = (LayoutManager) getLayoutManager(); - int count = layoutManager.getChildCount(); - - if (count == 0) { - return; - } - - int index = layoutManager.findCenterViewIndex(); - for (int i = 0; i < count; ++i) { - final View view = layoutManager.getChildAt(i); - ViewHolder holder = getChildViewHolder(view); - holder.onCenterProximity(i == index, animate); - } - final int position = getChildViewHolder(getChildAt(index)).getPosition(); - if (position != mPreviousCentral) { - for (OnScrollListener listener : mOnScrollListeners) { - listener.onCentralPositionChanged(position); - } - for (OnCentralPositionChangedListener listener : - mOnCentralPositionChangedListeners) { - listener.onCentralPositionChanged(position); - } - mPreviousCentral = position; - } - } - - // TODO: Move this to a separate class, so it can't directly interact with the WearableListView. - private class LayoutManager extends RecyclerView.LayoutManager { - private int mFirstPosition; - - private boolean mPushFirstHigher; - - private int mAbsoluteScroll; - - private boolean mUseOldViewTop = true; - - private boolean mWasZoomedIn = false; - - private RecyclerView.SmoothScroller mSmoothScroller; - - private RecyclerView.SmoothScroller mDefaultSmoothScroller; - - // We need to have another copy of the same method, because this one uses - // LayoutManager.getChildCount/getChildAt instead of View.getChildCount/getChildAt and - // they return different values. - private int findCenterViewIndex() { - // TODO(gruszczy): This could be easily optimized, so that we stop looking when we the - // distance starts growing again, instead of finding the closest. It would safe half of - // the loop. - int count = getChildCount(); - int index = -1; - int closest = Integer.MAX_VALUE; - int centerY = getCenterYPos(WearableListView.this); - for (int i = 0; i < count; ++i) { - final View child = getLayoutManager().getChildAt(i); - int childCenterY = getTop() + getCenterYPos(child); - final int distance = Math.abs(centerY - childCenterY); - if (distance < closest) { - closest = distance; - index = i; - } - } - if (index == -1) { - throw new IllegalStateException("Can't find central view."); - } - return index; - } - - @Override - public void onLayoutChildren(RecyclerView.Recycler recycler, State state) { - final int parentBottom = getHeight() - getPaddingBottom(); - // By default we assume this is the first run and the first element will be centered - // with optional initial offset. - int oldTop = getCentralViewTop() + mInitialOffset; - // Here we handle any other situation where we relayout or we want to achieve a - // specific layout of children. - if (mUseOldViewTop && getChildCount() > 0) { - // We are performing a relayout after we already had some children, because e.g. the - // contents of an adapter has changed. First we want to check, if the central item - // from before the layout is still here, because we want to preserve it. - int index = findCenterViewIndex(); - int position = getPosition(getChildAt(index)); - if (position == NO_POSITION) { - // Central item was removed. Let's find the first surviving item and use it - // as an anchor. - for (int i = 0, N = getChildCount(); index + i < N || index - i >= 0; ++i) { - View child = getChildAt(index + i); - if (child != null) { - position = getPosition(child); - if (position != NO_POSITION) { - index = index + i; - break; - } - } - child = getChildAt(index - i); - if (child != null) { - position = getPosition(child); - if (position != NO_POSITION) { - index = index - i; - break; - } - } - } - } - if (position == NO_POSITION) { - // None of the children survives the relayout, let's just use the top of the - // first one. - oldTop = getChildAt(0).getTop(); - int count = state.getItemCount(); - // Lets first make sure that the first position is not above the last element, - // which can happen if elements were removed. - while (mFirstPosition >= count && mFirstPosition > 0) { - mFirstPosition--; - } - } else { - // Some of the children survived the relayout. We will keep it in its place, - // but go through previous children and maybe add them. - if (!mWasZoomedIn) { - // If we were previously zoomed-in on a single item, ignore this and just - // use the default value set above. Reasoning: if we are still zoomed-in, - // oldTop will be ignored when laying out the single child element. If we - // are no longer zoomed in, then we want to position items using the top - // of the single item as if the single item was not zoomed in, which is - // equal to the default value. - oldTop = getChildAt(index).getTop(); - } - while (oldTop > getPaddingTop() && position > 0) { - position--; - oldTop -= getItemHeight(); - } - if (position == 0 && oldTop > getCentralViewTop()) { - // We need to handle special case where the first, central item was removed - // and now the first element is hanging below, instead of being nicely - // centered. - oldTop = getCentralViewTop(); - } - mFirstPosition = position; - } - } else if (mPushFirstHigher) { - // We are trying to position elements ourselves, so we force position of the first - // one. - oldTop = getCentralViewTop() - getItemHeight(); - } - - performLayoutChildren(recycler, state, parentBottom, oldTop); - - // Since the content might have changed, we need to adjust the absolute scroll in case - // some elements have disappeared or were added. - if (getChildCount() == 0) { - setAbsoluteScroll(0); - } else { - View child = getChildAt(findCenterViewIndex()); - setAbsoluteScroll(child.getTop() - getCentralViewTop() + getPosition(child) * - getItemHeight()); - } - - mUseOldViewTop = true; - mPushFirstHigher = false; - } - - private void performLayoutChildren(Recycler recycler, State state, int parentBottom, - int top) { - detachAndScrapAttachedViews(recycler); - - if (mMaximizeSingleItem && state.getItemCount() == 1) { - performLayoutOneChild(recycler, parentBottom); - mWasZoomedIn = true; - } else { - performLayoutMultipleChildren(recycler, state, parentBottom, top); - mWasZoomedIn = false; - } - - if (getChildCount() > 0) { - post(mNotifyChildrenPostLayoutRunnable); - } - } - - private void performLayoutOneChild(Recycler recycler, int parentBottom) { - final int right = getWidth() - getPaddingRight(); - View v = recycler.getViewForPosition(getFirstPosition()); - addView(v, 0); - measureZoomView(v); - v.layout(getPaddingLeft(), getPaddingTop(), right, parentBottom); - } - - private void performLayoutMultipleChildren(Recycler recycler, State state, int parentBottom, - int top) { - int bottom; - final int left = getPaddingLeft(); - final int right = getWidth() - getPaddingRight(); - final int count = state.getItemCount(); - // If we are laying out children with center element being different than the first, we - // need to start with previous child which appears half visible at the top. - for (int i = 0; getFirstPosition() + i < count; i++, top = bottom) { - if (top >= parentBottom) { - break; - } - View v = recycler.getViewForPosition(getFirstPosition() + i); - addView(v, i); - measureThirdView(v); - bottom = top + getItemHeight(); - v.layout(left, top, right, bottom); - } - } - - private void setAbsoluteScroll(int absoluteScroll) { - mAbsoluteScroll = absoluteScroll; - for (OnScrollListener listener : mOnScrollListeners) { - listener.onAbsoluteScrollChange(mAbsoluteScroll); - } - } - - private void measureView(View v, int height) { - final LayoutParams lp = (LayoutParams) v.getLayoutParams(); - final int widthSpec = getChildMeasureSpec(getWidth(), - getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin, lp.width, - canScrollHorizontally()); - final int heightSpec = getChildMeasureSpec(getHeight(), - getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin, - height, canScrollVertically()); - v.measure(widthSpec, heightSpec); - } - - private void measureThirdView(View v) { - measureView(v, (int) (1 + (float) getHeight() / THIRD)); - } - - private void measureZoomView(View v) { - measureView(v, getHeight()); - } - - @Override - public RecyclerView.LayoutParams generateDefaultLayoutParams() { - return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - } - - @Override - public boolean canScrollVertically() { - // Disable vertical scrolling when zoomed. - return getItemCount() != 1 || !mWasZoomedIn; - } - - @Override - public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, State state) { - // TODO(gruszczy): This code is shit, needs to be rewritten. - if (getChildCount() == 0) { - return 0; - } - int scrolled = 0; - final int left = getPaddingLeft(); - final int right = getWidth() - getPaddingRight(); - if (dy < 0) { - while (scrolled > dy) { - final View topView = getChildAt(0); - if (getFirstPosition() > 0) { - final int hangingTop = Math.max(-topView.getTop(), 0); - final int scrollBy = Math.min(scrolled - dy, hangingTop); - scrolled -= scrollBy; - offsetChildrenVertical(scrollBy); - if (getFirstPosition() > 0 && scrolled > dy) { - mFirstPosition--; - View v = recycler.getViewForPosition(getFirstPosition()); - addView(v, 0); - measureThirdView(v); - final int bottom = topView.getTop(); - final int top = bottom - getItemHeight(); - v.layout(left, top, right, bottom); - } else { - break; - } - } else { - mPushFirstHigher = false; - int maxScroll = mOverScrollListener!= null ? - getHeight() : getTopViewMaxTop(); - final int scrollBy = Math.min(-dy + scrolled, maxScroll - topView.getTop()); - scrolled -= scrollBy; - offsetChildrenVertical(scrollBy); - break; - } - } - } else if (dy > 0) { - final int parentHeight = getHeight(); - while (scrolled < dy) { - final View bottomView = getChildAt(getChildCount() - 1); - if (state.getItemCount() > mFirstPosition + getChildCount()) { - final int hangingBottom = - Math.max(bottomView.getBottom() - parentHeight, 0); - final int scrollBy = -Math.min(dy - scrolled, hangingBottom); - scrolled -= scrollBy; - offsetChildrenVertical(scrollBy); - if (scrolled < dy) { - View v = recycler.getViewForPosition(mFirstPosition + getChildCount()); - final int top = getChildAt(getChildCount() - 1).getBottom(); - addView(v); - measureThirdView(v); - final int bottom = top + getItemHeight(); - v.layout(left, top, right, bottom); - } else { - break; - } - } else { - final int scrollBy = - Math.max(-dy + scrolled, getHeight() / 2 - bottomView.getBottom()); - scrolled -= scrollBy; - offsetChildrenVertical(scrollBy); - break; - } - } - } - recycleViewsOutOfBounds(recycler); - setAbsoluteScroll(mAbsoluteScroll + scrolled); - return scrolled; - } - - @Override - public void scrollToPosition(int position) { - mUseOldViewTop = false; - if (position > 0) { - mFirstPosition = position - 1; - mPushFirstHigher = true; - } else { - mFirstPosition = position; - mPushFirstHigher = false; - } - requestLayout(); - } - - public void setCustomSmoothScroller(RecyclerView.SmoothScroller smoothScroller) { - mSmoothScroller = smoothScroller; - } - - public void clearCustomSmoothScroller() { - mSmoothScroller = null; - } - - public RecyclerView.SmoothScroller getDefaultSmoothScroller(RecyclerView recyclerView) { - if (mDefaultSmoothScroller == null) { - mDefaultSmoothScroller = new SmoothScroller( - recyclerView.getContext(), this); - } - return mDefaultSmoothScroller; - } - @Override - public void smoothScrollToPosition(RecyclerView recyclerView, State state, - int position) { - RecyclerView.SmoothScroller scroller = mSmoothScroller; - if (scroller == null) { - scroller = getDefaultSmoothScroller(recyclerView); - } - scroller.setTargetPosition(position); - startSmoothScroll(scroller); - } - - private void recycleViewsOutOfBounds(RecyclerView.Recycler recycler) { - final int childCount = getChildCount(); - final int parentWidth = getWidth(); - // Here we want to use real height, so we don't remove views that are only visible in - // padded section. - final int parentHeight = getHeight(); - boolean foundFirst = false; - int first = 0; - int last = 0; - for (int i = 0; i < childCount; i++) { - final View v = getChildAt(i); - if (v.hasFocus() || (v.getRight() >= 0 && v.getLeft() <= parentWidth && - v.getBottom() >= 0 && v.getTop() <= parentHeight)) { - if (!foundFirst) { - first = i; - foundFirst = true; - } - last = i; - } - } - for (int i = childCount - 1; i > last; i--) { - removeAndRecycleViewAt(i, recycler); - } - for (int i = first - 1; i >= 0; i--) { - removeAndRecycleViewAt(i, recycler); - } - if (getChildCount() == 0) { - mFirstPosition = 0; - } else if (first > 0) { - mPushFirstHigher = true; - mFirstPosition += first; - } - } - - public int getFirstPosition() { - return mFirstPosition; - } - - @Override - public void onAdapterChanged(RecyclerView.Adapter oldAdapter, - RecyclerView.Adapter newAdapter) { - removeAllViews(); - } - } - - /** - * Interface for receiving callbacks when WearableListView children become or cease to be the - * central item. - */ - public interface OnCenterProximityListener { - /** - * Called when this view becomes central item of the WearableListView. - * - * @param animate Whether you should animate your transition of the View to become the - * central item. If false, this is the initial setting and you should - * transition immediately. - */ - void onCenterPosition(boolean animate); - - /** - * Called when this view stops being the central item of the WearableListView. - * @param animate Whether you should animate your transition of the View to being - * non central item. If false, this is the initial setting and you should - * transition immediately. - */ - void onNonCenterPosition(boolean animate); - } - - /** - * Interface for listening for click events on WearableListView. - */ - public interface ClickListener { - /** - * Called when the central child of the WearableListView is tapped. - * @param view View that was clicked. - */ - public void onClick(ViewHolder view); - - /** - * Called when the user taps the top third of the WearableListView and no item is present - * there. This can happen when you are in initial state and the first, top-most item of the - * WearableListView is centered. - */ - public void onTopEmptyRegionClick(); - } - - /** - * @hide - */ - public interface OnOverScrollListener { - public void onOverScroll(); - } - - /** - * Interface for listening to WearableListView content scrolling. - */ - public interface OnScrollListener { - /** - * Called when the content is scrolled, reporting the relative scroll value. - * @param scroll Amount the content was scrolled. This is a delta from the previous - * position to the new position. - */ - public void onScroll(int scroll); - - /** - * Called when the content is scrolled, reporting the absolute scroll value. - * - * @deprecated BE ADVISED DO NOT USE THIS This might provide wrong values when contents - * of a RecyclerView change. - * - * @param scroll Absolute scroll position of the content inside the WearableListView. - */ - @Deprecated - public void onAbsoluteScrollChange(int scroll); - - /** - * Called when WearableListView's scroll state changes. - * - * @param scrollState The updated scroll state. One of {@link #SCROLL_STATE_IDLE}, - * {@link #SCROLL_STATE_DRAGGING} or {@link #SCROLL_STATE_SETTLING}. - */ - public void onScrollStateChanged(int scrollState); - - /** - * Called when the central item of the WearableListView changes. - * - * @param centralPosition Position of the item in the Adapter. - */ - public void onCentralPositionChanged(int centralPosition); - } - - /** - * A listener interface that can be added to the WearableListView to get notified when the - * central item is changed. - */ - public interface OnCentralPositionChangedListener { - /** - * Called when the central item of the WearableListView changes. - * - * @param centralPosition Position of the item in the Adapter. - */ - void onCentralPositionChanged(int centralPosition); - } - - /** - * Base class for adapters providing data for the WearableListView. For details refer to - * RecyclerView.Adapter. - */ - public static abstract class Adapter extends RecyclerView.Adapter<ViewHolder> { - } - - private static class SmoothScroller extends LinearSmoothScroller { - - private static final float MILLISECONDS_PER_INCH = 100f; - - private final LayoutManager mLayoutManager; - - public SmoothScroller(Context context, WearableListView.LayoutManager manager) { - super(context); - mLayoutManager = manager; - } - - @Override - protected void onStart() { - super.onStart(); - } - - // TODO: (mindyp): when flinging, return the dydt that triggered the fling. - @Override - protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { - return MILLISECONDS_PER_INCH / displayMetrics.densityDpi; - } - - @Override - public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int - snapPreference) { - // Snap to center. - return (boxStart + boxEnd) / 2 - (viewStart + viewEnd) / 2; - } - - @Override - public PointF computeScrollVectorForPosition(int targetPosition) { - if (targetPosition < mLayoutManager.getFirstPosition()) { - return new PointF(0, -1); - } else { - return new PointF(0, 1); - } - } - } - - /** - * Wrapper around items displayed in the list view. {@link .Adapter} must return objects that - * are instances of this class. Consider making the wrapped View implement - * {@link .OnCenterProximityListener} if you want to receive a callback when it becomes or - * ceases to be the central item in the WearableListView. - */ - public static class ViewHolder extends RecyclerView.ViewHolder { - public ViewHolder(View itemView) { - super(itemView); - } - - /** - * Called when the wrapped view is becoming or ceasing to be the central item of the - * WearableListView. - * - * Retained as protected for backwards compatibility. - * - * @hide - */ - protected void onCenterProximity(boolean isCentralItem, boolean animate) { - if (!(itemView instanceof OnCenterProximityListener)) { - return; - } - OnCenterProximityListener item = (OnCenterProximityListener) itemView; - if (isCentralItem) { - item.onCenterPosition(animate); - } else { - item.onNonCenterPosition(animate); - } - } - } - - private class SetScrollVerticallyProperty extends Property<WearableListView, Integer> { - public SetScrollVerticallyProperty() { - super(Integer.class, "scrollVertically"); - } - - @Override - public Integer get(WearableListView wearableListView) { - return wearableListView.mLastScrollChange; - } - - @Override - public void set(WearableListView wearableListView, Integer value) { - wearableListView.setScrollVertically(value); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/AppPermissionGroup.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/AppPermissionGroup.java deleted file mode 100644 index 6b3a76071f5869f138b62a8d0766059d6ff5f172..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/AppPermissionGroup.java +++ /dev/null @@ -1,1001 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.model; - -import static android.app.AppOpsManager.MODE_ALLOWED; -import static android.app.AppOpsManager.MODE_FOREGROUND; -import static android.app.AppOpsManager.MODE_IGNORED; - -import android.annotation.StringRes; -import android.annotation.SystemApi; -import android.app.ActivityManager; -import android.app.AppOpsManager; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageItemInfo; -import android.content.pm.PackageManager; -import android.content.pm.PermissionGroupInfo; -import android.content.pm.PermissionInfo; -import android.content.res.ResourceId; -import android.os.Build; -import android.os.Process; -import android.os.UserHandle; -import android.util.ArrayMap; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.utils.ArrayUtils; -import com.android.packageinstaller.permission.utils.LocationUtils; - -import java.text.Collator; -import java.util.ArrayList; -import java.util.List; - -/** - * All permissions of a permission group that are requested by an app. - * - * <p>Some permissions only grant access to the protected resource while the app is running in the - * foreground. These permissions are considered "split" into this foreground and a matching - * "background" permission. - * - * <p>All background permissions of the group are not in the main group and will not be affected - * by operations on the group. The background permissions can be found in the {@link - * #getBackgroundPermissions() background permissions group}. - */ -public final class AppPermissionGroup implements Comparable<AppPermissionGroup> { - private static final String PLATFORM_PACKAGE_NAME = "android"; - - private static final String KILL_REASON_APP_OP_CHANGE = "Permission related app op changed"; - - private final Context mContext; - private final UserHandle mUserHandle; - private final PackageManager mPackageManager; - private final AppOpsManager mAppOps; - private final ActivityManager mActivityManager; - private final Collator mCollator; - - private final PackageInfo mPackageInfo; - private final String mName; - private final String mDeclaringPackage; - private final CharSequence mLabel; - private final @StringRes int mRequest; - private final @StringRes int mRequestDetail; - private final @StringRes int mBackgroundRequest; - private final @StringRes int mBackgroundRequestDetail; - private final CharSequence mDescription; - private final ArrayMap<String, Permission> mPermissions = new ArrayMap<>(); - private final String mIconPkg; - private final int mIconResId; - - /** - * Some permissions are split into foreground and background permission. All non-split and - * foreground permissions are in {@link #mPermissions}, all background permissions are in - * this field. - */ - private AppPermissionGroup mBackgroundPermissions; - - private final boolean mAppSupportsRuntimePermissions; - private final boolean mIsEphemeralApp; - private boolean mContainsEphemeralPermission; - private boolean mContainsPreRuntimePermission; - - /** - * Does this group contain at least one permission that is split into a foreground and - * background permission? This does not necessarily mean that the app also requested the - * background permission. - */ - private boolean mHasPermissionWithBackgroundMode; - - public static AppPermissionGroup create(Context context, PackageInfo packageInfo, - String permissionName) { - PermissionInfo permissionInfo; - try { - permissionInfo = context.getPackageManager().getPermissionInfo(permissionName, 0); - } catch (PackageManager.NameNotFoundException e) { - return null; - } - - if ((permissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) - != PermissionInfo.PROTECTION_DANGEROUS - || (permissionInfo.flags & PermissionInfo.FLAG_INSTALLED) == 0 - || (permissionInfo.flags & PermissionInfo.FLAG_REMOVED) != 0) { - return null; - } - - PackageItemInfo groupInfo = permissionInfo; - if (permissionInfo.group != null) { - try { - groupInfo = context.getPackageManager().getPermissionGroupInfo( - permissionInfo.group, 0); - } catch (PackageManager.NameNotFoundException e) { - /* ignore */ - } - } - - List<PermissionInfo> permissionInfos = null; - if (groupInfo instanceof PermissionGroupInfo) { - try { - permissionInfos = context.getPackageManager().queryPermissionsByGroup( - groupInfo.name, 0); - } catch (PackageManager.NameNotFoundException e) { - /* ignore */ - } - } - - return create(context, packageInfo, groupInfo, permissionInfos, - Process.myUserHandle()); - } - - public static AppPermissionGroup create(Context context, PackageInfo packageInfo, - PackageItemInfo groupInfo, List<PermissionInfo> permissionInfos, - UserHandle userHandle) { - - AppPermissionGroup group = new AppPermissionGroup(context, packageInfo, groupInfo.name, - groupInfo.packageName, groupInfo.loadLabel(context.getPackageManager()), - loadGroupDescription(context, groupInfo), getRequest(groupInfo), - getRequestDetail(groupInfo), getBackgroundRequest(groupInfo), - getBackgroundRequestDetail(groupInfo), groupInfo.packageName, groupInfo.icon, - userHandle); - - if (groupInfo instanceof PermissionInfo) { - permissionInfos = new ArrayList<>(); - permissionInfos.add((PermissionInfo) groupInfo); - } - - if (permissionInfos == null || permissionInfos.isEmpty()) { - return null; - } - - // Parse and create permissions reqested by the app - ArrayMap<String, Permission> allPermissions = new ArrayMap<>(); - final int permissionCount = packageInfo.requestedPermissions.length; - for (int i = 0; i < permissionCount; i++) { - String requestedPermission = packageInfo.requestedPermissions[i]; - - PermissionInfo requestedPermissionInfo = null; - - for (PermissionInfo permissionInfo : permissionInfos) { - if (requestedPermission.equals(permissionInfo.name)) { - requestedPermissionInfo = permissionInfo; - break; - } - } - - if (requestedPermissionInfo == null) { - continue; - } - - // Collect only runtime permissions. - if ((requestedPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) - != PermissionInfo.PROTECTION_DANGEROUS) { - continue; - } - - // Don't allow toggling non-platform permission groups for legacy apps via app ops. - if (packageInfo.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1 - && !PLATFORM_PACKAGE_NAME.equals(groupInfo.packageName)) { - continue; - } - - final boolean granted = (packageInfo.requestedPermissionsFlags[i] - & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0; - - final String appOp = PLATFORM_PACKAGE_NAME.equals(requestedPermissionInfo.packageName) - ? AppOpsManager.permissionToOp(requestedPermissionInfo.name) : null; - - final boolean appOpAllowed = appOp != null - && context.getSystemService(AppOpsManager.class).checkOpNoThrow(appOp, - packageInfo.applicationInfo.uid, packageInfo.packageName) - == MODE_ALLOWED; - - final int flags = context.getPackageManager().getPermissionFlags( - requestedPermission, packageInfo.packageName, userHandle); - - Permission permission = new Permission(requestedPermission, - requestedPermissionInfo.backgroundPermission, granted, - appOp, appOpAllowed, flags, requestedPermissionInfo.protectionLevel); - - if (requestedPermissionInfo.backgroundPermission != null) { - group.mHasPermissionWithBackgroundMode = true; - } - - allPermissions.put(requestedPermission, permission); - } - - int numPermissions = allPermissions.size(); - if (numPermissions == 0) { - return null; - } - - // Link up foreground and background permissions - for (int i = 0; i < allPermissions.size(); i++) { - Permission permission = allPermissions.valueAt(i); - - if (permission.getBackgroundPermissionName() != null) { - Permission backgroundPermission = allPermissions.get( - permission.getBackgroundPermissionName()); - - if (backgroundPermission != null) { - backgroundPermission.addForegroundPermissions(permission); - permission.setBackgroundPermission(backgroundPermission); - } - } - } - - // Add permissions found to this group - for (int i = 0; i < numPermissions; i++) { - Permission permission = allPermissions.valueAt(i); - - if (permission.isBackgroundPermission()) { - if (group.getBackgroundPermissions() == null) { - group.mBackgroundPermissions = new AppPermissionGroup(group.mContext, - group.getApp(), group.getName(), group.getDeclaringPackage(), - group.getLabel(), group.getDescription(), group.getRequest(), - group.getRequestDetail(), group.getBackgroundRequest(), - group.getBackgroundRequestDetail(), group.getIconPkg(), - group.getIconResId(), UserHandle.of(group.getUserId())); - } - - group.getBackgroundPermissions().addPermission(permission); - } else { - group.addPermission(permission); - } - } - - return group; - } - - private static @StringRes int getRequest(PackageItemInfo group) { - if (group instanceof PermissionGroupInfo) { - return ((PermissionGroupInfo) group).requestRes; - } else if (group instanceof PermissionInfo) { - return ((PermissionInfo) group).requestRes; - } else { - return 0; - } - } - - private static CharSequence loadGroupDescription(Context context, PackageItemInfo group) { - CharSequence description = null; - if (group instanceof PermissionGroupInfo) { - description = ((PermissionGroupInfo) group).loadDescription( - context.getPackageManager()); - } else if (group instanceof PermissionInfo) { - description = ((PermissionInfo) group).loadDescription( - context.getPackageManager()); - } - - if (description == null || description.length() <= 0) { - description = context.getString(R.string.default_permission_description); - } - - return description; - } - - private AppPermissionGroup(Context context, PackageInfo packageInfo, String name, - String declaringPackage, CharSequence label, CharSequence description, - @StringRes int request, @StringRes int requestDetail, - @StringRes int backgroundRequest, @StringRes int backgroundRequestDetail, - String iconPkg, int iconResId, UserHandle userHandle) { - mContext = context; - mUserHandle = userHandle; - mPackageManager = mContext.getPackageManager(); - mPackageInfo = packageInfo; - mAppSupportsRuntimePermissions = packageInfo.applicationInfo - .targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1; - mIsEphemeralApp = packageInfo.applicationInfo.isInstantApp(); - mAppOps = context.getSystemService(AppOpsManager.class); - mActivityManager = context.getSystemService(ActivityManager.class); - mDeclaringPackage = declaringPackage; - mName = name; - mLabel = label; - mDescription = description; - mCollator = Collator.getInstance( - context.getResources().getConfiguration().getLocales().get(0)); - mRequest = request; - mRequestDetail = requestDetail; - mBackgroundRequest = backgroundRequest; - mBackgroundRequestDetail = backgroundRequestDetail; - if (iconResId != 0) { - mIconPkg = iconPkg; - mIconResId = iconResId; - } else { - mIconPkg = context.getPackageName(); - mIconResId = R.drawable.ic_perm_device_info; - } - } - - public boolean doesSupportRuntimePermissions() { - return mAppSupportsRuntimePermissions; - } - - public boolean isGrantingAllowed() { - return (!mIsEphemeralApp || mContainsEphemeralPermission) - && (mAppSupportsRuntimePermissions || mContainsPreRuntimePermission); - } - - public boolean isReviewRequired() { - if (mAppSupportsRuntimePermissions) { - return false; - } - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - Permission permission = mPermissions.valueAt(i); - if (permission.isReviewRequired()) { - return true; - } - } - return false; - } - - public void resetReviewRequired() { - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - Permission permission = mPermissions.valueAt(i); - if (permission.isReviewRequired()) { - permission.resetReviewRequired(); - mPackageManager.updatePermissionFlags(permission.getName(), - mPackageInfo.packageName, - PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, - 0, mUserHandle); - } - } - } - - public boolean hasGrantedByDefaultPermission() { - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - Permission permission = mPermissions.valueAt(i); - if (permission.isGrantedByDefault()) { - return true; - } - } - return false; - } - - public PackageInfo getApp() { - return mPackageInfo; - } - - public String getName() { - return mName; - } - - public String getDeclaringPackage() { - return mDeclaringPackage; - } - - public String getIconPkg() { - return mIconPkg; - } - - public int getIconResId() { - return mIconResId; - } - - public CharSequence getLabel() { - return mLabel; - } - - /** - * @hide - * @return The resource Id of the request string. - */ - @SystemApi - public @StringRes int getRequest() { - return mRequest; - } - - /** - * Extract the (subtitle) message explaining to the user that the permission is only granted to - * the apps running in the foreground. - * - * @param info The package item info to extract the message from - * - * @return the message of {@link ResourceId#ID_NULL} if unset - */ - private static @StringRes int getRequestDetail(PackageItemInfo info) { - if (info instanceof PermissionGroupInfo) { - return ((PermissionGroupInfo) info).requestDetailResourceId; - } else { - return ResourceId.ID_NULL; - } - } - - /** - * Get the (subtitle) message explaining to the user that the permission is only granted to - * the apps running in the foreground. - * - * @return the message of {@link ResourceId#ID_NULL} if unset - */ - public @StringRes int getRequestDetail() { - return mRequestDetail; - } - - /** - * Extract the title of the dialog explaining to the user that the permission is granted while - * the app is in background and in foreground. - * - * @param info The package item info to extract the message from - * - * @return the message of {@link ResourceId#ID_NULL} if unset - */ - private static @StringRes int getBackgroundRequest(PackageItemInfo info) { - if (info instanceof PermissionGroupInfo) { - return ((PermissionGroupInfo) info).backgroundRequestResourceId; - } else { - return ResourceId.ID_NULL; - } - } - - /** - * Get the title of the dialog explaining to the user that the permission is granted while - * the app is in background and in foreground. - * - * @return the message of {@link ResourceId#ID_NULL} if unset - */ - public @StringRes int getBackgroundRequest() { - return mBackgroundRequest; - } - - /** - * Extract the (subtitle) message explaining to the user that the she/he is about to allow the - * app to have background access. - * - * @param info The package item info to extract the message from - * - * @return the message of {@link ResourceId#ID_NULL} if unset - */ - private static @StringRes int getBackgroundRequestDetail(PackageItemInfo info) { - if (info instanceof PermissionGroupInfo) { - return ((PermissionGroupInfo) info).backgroundRequestDetailResourceId; - } else { - return ResourceId.ID_NULL; - } - } - - /** - * Get the (subtitle) message explaining to the user that the she/he is about to allow the - * app to have background access. - * - * @return the message of {@link ResourceId#ID_NULL} if unset - */ - public @StringRes int getBackgroundRequestDetail() { - return mBackgroundRequestDetail; - } - - public CharSequence getDescription() { - return mDescription; - } - - public int getUserId() { - return mUserHandle.getIdentifier(); - } - - public boolean hasPermission(String permission) { - return mPermissions.get(permission) != null; - } - - public boolean areRuntimePermissionsGranted() { - return areRuntimePermissionsGranted(null); - } - - public boolean areRuntimePermissionsGranted(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 true; - } - } else if (permission.isGranted() - && (!permission.affectsAppOp() || permission.isAppOpAllowed()) - && !permission.isReviewRequired()) { - return true; - } - } - return false; - } - - public boolean grantRuntimePermissions(boolean fixedByTheUser) { - return grantRuntimePermissions(fixedByTheUser, null); - } - - /** - * Allow the app op for a permission/uid. - * - * <p>There are three cases: - * <dl> - * <dt>The permission is not split into foreground/background</dt> - * <dd>The app op matching the permission will be set to {@link AppOpsManager#MODE_ALLOWED}</dd> - * <dt>The permission is a foreground permission:</dt> - * <dd><dl><dt>The background permission permission is granted</dt> - * <dd>The app op matching the permission will be set to {@link AppOpsManager#MODE_ALLOWED}</dd> - * <dt>The background permission permission is <u>not</u> granted</dt> - * <dd>The app op matching the permission will be set to - * {@link AppOpsManager#MODE_FOREGROUND}</dd> - * </dl></dd> - * <dt>The permission is a background permission:</dt> - * <dd>All granted foreground permissions for this background permission will be set to - * {@link AppOpsManager#MODE_ALLOWED}</dd> - * </dl> - * - * @param permission The permission which has an appOps that should be allowed - * @param uid The uid of the process the app op if for - */ - private void allowAppOp(Permission permission, int uid) { - if (permission.isBackgroundPermission()) { - ArrayList<Permission> foregroundPermissions = permission.getForegroundPermissions(); - - int numForegroundPermissions = foregroundPermissions.size(); - for (int i = 0; i < numForegroundPermissions; i++) { - Permission foregroundPermission = foregroundPermissions.get(i); - if (foregroundPermission.isAppOpAllowed()) { - mAppOps.setUidMode(foregroundPermission.getAppOp(), uid, MODE_ALLOWED); - } - } - } else { - if (permission.hasBackgroundPermission()) { - Permission backgroundPermission = permission.getBackgroundPermission(); - - if (backgroundPermission == null) { - // The app requested a permission that has a background permission but it did - // not request the background permission, hence it can never get background - // access - mAppOps.setUidMode(permission.getAppOp(), uid, MODE_FOREGROUND); - } else { - if (backgroundPermission.isAppOpAllowed()) { - mAppOps.setUidMode(permission.getAppOp(), uid, MODE_ALLOWED); - } else { - mAppOps.setUidMode(permission.getAppOp(), uid, MODE_FOREGROUND); - } - } - } else { - mAppOps.setUidMode(permission.getAppOp(), uid, MODE_ALLOWED); - } - } - } - - /** - * Grant permissions of the group. - * - * <p>This also automatically grants all app ops for permissions that have app ops. - * <p>This does <u>only</u> grant permissions in {@link #mPermissions}, i.e. usually not - * the background permissions. - * - * @param fixedByTheUser If the user requested that she/he does not want to be asked again - * @param filterPermissions If {@code null} all permissions of the group will be granted. - * Otherwise only permissions in {@code filterPermissions} will be - * granted. - * - * @return {@code true} iff all permissions of this group could be granted. - */ - public boolean grantRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) { - final int uid = mPackageInfo.applicationInfo.uid; - - // We toggle permissions only to apps that support runtime - // permissions, otherwise we toggle the app op corresponding - // to the permission if the permission is granted to the app. - for (Permission permission : mPermissions.values()) { - if (filterPermissions != null - && !ArrayUtils.contains(filterPermissions, permission.getName())) { - continue; - } - - if (!permission.isGrantingAllowed(mIsEphemeralApp, mAppSupportsRuntimePermissions)) { - // Skip unallowed permissions. - continue; - } - - if (mAppSupportsRuntimePermissions) { - // Do not touch permissions fixed by the system. - if (permission.isSystemFixed()) { - return false; - } - - // Ensure the permission app op enabled before the permission grant. - if (permission.affectsAppOp() && !permission.isAppOpAllowed()) { - permission.setAppOpAllowed(true); - allowAppOp(permission, uid); - } - - // Grant the permission if needed. - if (!permission.isGranted()) { - permission.setGranted(true); - mPackageManager.grantRuntimePermission(mPackageInfo.packageName, - permission.getName(), mUserHandle); - } - - // Update the permission flags. - if (!fixedByTheUser) { - // Now the apps can ask for the permission as the user - // no longer has it fixed in a denied state. - if (permission.isUserFixed() || permission.isUserSet()) { - permission.setUserFixed(false); - permission.setUserSet(false); - mPackageManager.updatePermissionFlags(permission.getName(), - mPackageInfo.packageName, - PackageManager.FLAG_PERMISSION_USER_FIXED - | PackageManager.FLAG_PERMISSION_USER_SET, - 0, mUserHandle); - } - } - } else { - // Legacy apps cannot have a not granted permission but just in case. - if (!permission.isGranted()) { - continue; - } - - int killUid = -1; - int mask = 0; - - // If the permissions has no corresponding app op, then it is a - // third-party one and we do not offer toggling of such permissions. - if (permission.affectsAppOp()) { - if (!permission.isAppOpAllowed()) { - permission.setAppOpAllowed(true); - allowAppOp(permission, uid); - - // Legacy apps do not know that they have to retry access to a - // resource due to changes in runtime permissions (app ops in this - // case). Therefore, we restart them on app op change, so they - // can pick up the change. - killUid = uid; - } - - // Mark that the permission should not be be granted on upgrade - // when the app begins supporting runtime permissions. - if (permission.shouldRevokeOnUpgrade()) { - permission.setRevokeOnUpgrade(false); - mask |= PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE; - } - } - - // Granting a permission explicitly means the user already - // reviewed it so clear the review flag on every grant. - if (permission.isReviewRequired()) { - permission.resetReviewRequired(); - mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; - } - - if (mask != 0) { - mPackageManager.updatePermissionFlags(permission.getName(), - mPackageInfo.packageName, mask, 0, mUserHandle); - } - - if (killUid != -1) { - mActivityManager.killUid(uid, KILL_REASON_APP_OP_CHANGE); - } - } - } - - return true; - } - - public boolean revokeRuntimePermissions(boolean fixedByTheUser) { - return revokeRuntimePermissions(fixedByTheUser, null); - } - - /** - * Disallow the app op for a permission/uid. - * - * <p>There are three cases: - * <dl> - * <dt>The permission is not split into foreground/background</dt> - * <dd>The app op matching the permission will be set to {@link AppOpsManager#MODE_IGNORED}</dd> - * <dt>The permission is a foreground permission:</dt> - * <dd>The app op matching the permission will be set to {@link AppOpsManager#MODE_IGNORED}</dd> - * <dt>The permission is a background permission:</dt> - * <dd>All granted foreground permissions for this background permission will be set to - * {@link AppOpsManager#MODE_FOREGROUND}</dd> - * </dl> - * - * @param permission The permission which has an appOps that should be disallowed - * @param uid The uid of the process the app op if for - */ - private void disallowAppOp(Permission permission, int uid) { - if (permission.isBackgroundPermission()) { - ArrayList<Permission> foregroundPermissions = permission.getForegroundPermissions(); - - int numForegroundPermissions = foregroundPermissions.size(); - for (int i = 0; i < numForegroundPermissions; i++) { - Permission foregroundPermission = foregroundPermissions.get(i); - if (foregroundPermission.isAppOpAllowed()) { - mAppOps.setUidMode(foregroundPermission.getAppOp(), uid, MODE_FOREGROUND); - } - } - } else { - mAppOps.setUidMode(permission.getAppOp(), uid, MODE_IGNORED); - } - } - - /** - * Revoke permissions of the group. - * - * <p>This also disallows all app ops for permissions that have app ops. - * <p>This does <u>only</u> revoke permissions in {@link #mPermissions}, i.e. usually not - * the background permissions. - * - * @param fixedByTheUser If the user requested that she/he does not want to be asked again - * @param filterPermissions If {@code null} all permissions of the group will be revoked. - * Otherwise only permissions in {@code filterPermissions} will be - * revoked. - * - * @return {@code true} iff all permissions of this group could be revoked. - */ - public boolean revokeRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) { - final int uid = mPackageInfo.applicationInfo.uid; - - // We toggle permissions only to apps that support runtime - // permissions, otherwise we toggle the app op corresponding - // to the permission if the permission is granted to the app. - for (Permission permission : mPermissions.values()) { - if (filterPermissions != null - && !ArrayUtils.contains(filterPermissions, permission.getName())) { - continue; - } - - if (mAppSupportsRuntimePermissions) { - // Do not touch permissions fixed by the system. - if (permission.isSystemFixed()) { - return false; - } - - // Revoke the permission if needed. - if (permission.isGranted()) { - permission.setGranted(false); - mPackageManager.revokeRuntimePermission(mPackageInfo.packageName, - permission.getName(), mUserHandle); - } - - // Update the permission flags. - if (fixedByTheUser) { - // Take a note that the user fixed the permission. - if (permission.isUserSet() || !permission.isUserFixed()) { - permission.setUserSet(false); - permission.setUserFixed(true); - mPackageManager.updatePermissionFlags(permission.getName(), - mPackageInfo.packageName, - PackageManager.FLAG_PERMISSION_USER_SET - | PackageManager.FLAG_PERMISSION_USER_FIXED, - PackageManager.FLAG_PERMISSION_USER_FIXED, - mUserHandle); - } - } else { - if (!permission.isUserSet() || permission.isUserFixed()) { - permission.setUserSet(true); - permission.setUserFixed(false); - // Take a note that the user already chose once. - mPackageManager.updatePermissionFlags(permission.getName(), - mPackageInfo.packageName, - PackageManager.FLAG_PERMISSION_USER_SET - | PackageManager.FLAG_PERMISSION_USER_FIXED, - PackageManager.FLAG_PERMISSION_USER_SET, - mUserHandle); - } - } - - if (permission.affectsAppOp()) { - permission.setAppOpAllowed(false); - disallowAppOp(permission, uid); - } - } else { - // Legacy apps cannot have a non-granted permission but just in case. - if (!permission.isGranted()) { - continue; - } - - int mask = 0; - int flags = 0; - int killUid = -1; - - // If the permission has no corresponding app op, then it is a - // third-party one and we do not offer toggling of such permissions. - if (permission.affectsAppOp()) { - if (permission.isAppOpAllowed()) { - permission.setAppOpAllowed(false); - disallowAppOp(permission, uid); - - // Disabling an app op may put the app in a situation in which it - // has a handle to state it shouldn't have, so we have to kill the - // app. This matches the revoke runtime permission behavior. - killUid = uid; - } - - // Mark that the permission should not be granted on upgrade - // when the app begins supporting runtime permissions. - if (!permission.shouldRevokeOnUpgrade()) { - permission.setRevokeOnUpgrade(true); - mask |= PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE; - flags |= PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE; - } - } - - if (mask != 0) { - mPackageManager.updatePermissionFlags(permission.getName(), - mPackageInfo.packageName, mask, flags, mUserHandle); - } - - if (killUid != -1) { - mActivityManager.killUid(uid, KILL_REASON_APP_OP_CHANGE); - } - } - } - - return true; - } - - public void setPolicyFixed() { - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - Permission permission = mPermissions.valueAt(i); - permission.setPolicyFixed(true); - mPackageManager.updatePermissionFlags(permission.getName(), - mPackageInfo.packageName, - PackageManager.FLAG_PERMISSION_POLICY_FIXED, - PackageManager.FLAG_PERMISSION_POLICY_FIXED, - mUserHandle); - } - } - - public ArrayList<Permission> getPermissions() { - return new ArrayList<>(mPermissions.values()); - } - - /** - * @return An {@link AppPermissionGroup}-object that contains all background permissions for - * this group. - */ - public AppPermissionGroup getBackgroundPermissions() { - return mBackgroundPermissions; - } - - /** - * @return {@code true} iff the app request at least one permission in this group that has a - * background permission. It is possible that the app does not request the matching background - * permission and hence will only ever get foreground access, never background access. - */ - public boolean hasPermissionWithBackgroundMode() { - return mHasPermissionWithBackgroundMode; - } - - /** - * Whether this is group that contains all the background permission for regular permission - * group. - * - * @return {@code true} iff this is a background permission group. - * - * @see #getBackgroundPermissions() - */ - public boolean isBackgroundGroup() { - return mPermissions.valueAt(0).isBackgroundPermission(); - } - - public int getFlags() { - int flags = 0; - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - Permission permission = mPermissions.valueAt(i); - flags |= permission.getFlags(); - } - return flags; - } - - public boolean isUserFixed() { - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - Permission permission = mPermissions.valueAt(i); - if (permission.isUserFixed()) { - return true; - } - } - return false; - } - - public boolean isPolicyFixed() { - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - Permission permission = mPermissions.valueAt(i); - if (permission.isPolicyFixed()) { - return true; - } - } - return false; - } - - public boolean isUserSet() { - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - Permission permission = mPermissions.valueAt(i); - if (permission.isUserSet()) { - return true; - } - } - return false; - } - - public boolean isSystemFixed() { - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - Permission permission = mPermissions.valueAt(i); - if (permission.isSystemFixed()) { - return true; - } - } - return false; - } - - @Override - public int compareTo(AppPermissionGroup another) { - final int result = mCollator.compare(mLabel.toString(), another.mLabel.toString()); - if (result == 0) { - // Unbadged before badged. - return mPackageInfo.applicationInfo.uid - - another.mPackageInfo.applicationInfo.uid; - } - return result; - } - - @Override - public boolean equals(Object o) { - if (o == null || !(o instanceof AppPermissionGroup)) { - return false; - } - - AppPermissionGroup other = (AppPermissionGroup) o; - return mName.equals(other.mName) - && mPackageInfo.packageName.equals(other.mPackageInfo.packageName) - && mUserHandle.equals(other.mUserHandle); - } - - @Override - public int hashCode() { - return mName.hashCode() + mPackageInfo.packageName.hashCode() + mUserHandle.hashCode(); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(getClass().getSimpleName()); - builder.append("{name=").append(mName); - if (mBackgroundPermissions != null) { - builder.append(", <has background permissions>}"); - } - if (!mPermissions.isEmpty()) { - builder.append(", <has permissions>}"); - } else { - builder.append('}'); - } - return builder.toString(); - } - - private void addPermission(Permission permission) { - mPermissions.put(permission.getName(), permission); - if (permission.isEphemeral()) { - mContainsEphemeralPermission = true; - } - if (!permission.isRuntimeOnly()) { - mContainsPreRuntimePermission = true; - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/AppPermissions.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/AppPermissions.java deleted file mode 100644 index 880ff26ebec4ac74a195c6cf6b7d0b768b36af3c..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/AppPermissions.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.model; - -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageItemInfo; -import android.content.pm.PackageManager; -import android.text.BidiFormatter; -import android.util.ArrayMap; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * An app that requests permissions. - * - * <p>Allows to query all permission groups of the app and which permission belongs to which group. - */ -public final class AppPermissions { - /** - * All permission groups the app requests. Background permission groups are attached to their - * foreground groups. - */ - private final ArrayList<AppPermissionGroup> mGroups = new ArrayList<>(); - - /** Cache: group name -> group */ - private final ArrayMap<String, AppPermissionGroup> mGroupNameToGroup = new ArrayMap<>(); - - /** Cache: permission name -> group. Might point to background group */ - private final ArrayMap<String, AppPermissionGroup> mPermissionNameToGroup = new ArrayMap<>(); - - private final Context mContext; - - private final CharSequence mAppLabel; - - private final Runnable mOnErrorCallback; - - private final boolean mSortGroups; - - private PackageInfo mPackageInfo; - - public AppPermissions(Context context, PackageInfo packageInfo, boolean sortGroups, - Runnable onErrorCallback) { - mContext = context; - mPackageInfo = packageInfo; - mAppLabel = BidiFormatter.getInstance().unicodeWrap( - packageInfo.applicationInfo.loadSafeLabel(context.getPackageManager(), - PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX, - PackageItemInfo.SAFE_LABEL_FLAG_TRIM - | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE) - .toString()); - mSortGroups = sortGroups; - mOnErrorCallback = onErrorCallback; - loadPermissionGroups(); - } - - public PackageInfo getPackageInfo() { - return mPackageInfo; - } - - public void refresh() { - loadPackageInfo(); - loadPermissionGroups(); - } - - public CharSequence getAppLabel() { - return mAppLabel; - } - - public AppPermissionGroup getPermissionGroup(String name) { - return mGroupNameToGroup.get(name); - } - - public List<AppPermissionGroup> getPermissionGroups() { - return mGroups; - } - - public boolean isReviewRequired() { - final int groupCount = mGroups.size(); - for (int i = 0; i < groupCount; i++) { - AppPermissionGroup group = mGroups.get(i); - if (group.isReviewRequired()) { - return true; - } - } - return false; - } - - private void loadPackageInfo() { - try { - mPackageInfo = mContext.getPackageManager().getPackageInfo( - mPackageInfo.packageName, PackageManager.GET_PERMISSIONS); - } catch (PackageManager.NameNotFoundException e) { - if (mOnErrorCallback != null) { - mOnErrorCallback.run(); - } - } - } - - /** - * Add all individual permissions of the {@code group} to the {@link #mPermissionNameToGroup} - * lookup table. - * - * @param group The group of permissions to add - */ - private void addAllPermissions(AppPermissionGroup group) { - ArrayList<Permission> perms = group.getPermissions(); - - int numPerms = perms.size(); - for (int permNum = 0; permNum < numPerms; permNum++) { - mPermissionNameToGroup.put(perms.get(permNum).getName(), group); - } - } - - private void loadPermissionGroups() { - mGroups.clear(); - mGroupNameToGroup.clear(); - mPermissionNameToGroup.clear(); - - if (mPackageInfo.requestedPermissions != null) { - for (String requestedPerm : mPackageInfo.requestedPermissions) { - if (getGroupForPermission(requestedPerm) == null) { - AppPermissionGroup group = AppPermissionGroup.create(mContext, mPackageInfo, - requestedPerm); - if (group == null) { - continue; - } - - mGroups.add(group); - mGroupNameToGroup.put(group.getName(), group); - - addAllPermissions(group); - - AppPermissionGroup backgroundGroup = group.getBackgroundPermissions(); - if (backgroundGroup != null) { - addAllPermissions(backgroundGroup); - } - } - } - - if (mSortGroups) { - Collections.sort(mGroups); - } - } - } - - /** - * Find the group a permission belongs to. - * - * <p>The group found might be a background group. - * - * @param permission The name of the permission - * - * @return The group the permission belongs to - */ - public AppPermissionGroup getGroupForPermission(String permission) { - return mPermissionNameToGroup.get(permission); - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/Permission.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/Permission.java deleted file mode 100644 index 2e555f32e289fbcbbaaab0ed173af34e3dc5a580..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/Permission.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.model; - -import android.content.pm.PackageManager; -import android.content.pm.PermissionInfo; - -import java.util.ArrayList; - -/** - * A permission and it's properties. - * - * @see AppPermissionGroup - */ -public final class Permission { - private final String mName; - private final String mBackgroundPermissionName; - private final String mAppOp; - - private boolean mGranted; - private boolean mAppOpAllowed; - private int mFlags; - private boolean mIsEphemeral; - private boolean mIsRuntimeOnly; - private Permission mBackgroundPermission; - private ArrayList<Permission> mForegroundPermissions; - - public Permission(String name, String backgroundPermissionName, boolean granted, - String appOp, boolean appOpAllowed, int flags, int protectionLevel) { - mName = name; - mBackgroundPermissionName = backgroundPermissionName; - mGranted = granted; - mAppOp = appOp; - mAppOpAllowed = appOpAllowed; - mFlags = flags; - mIsEphemeral = (protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0; - mIsRuntimeOnly = (protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0; - } - - /** - * Mark this permission as background permission for {@code foregroundPermissions}. - * - * @param foregroundPermission The foreground permission - */ - public void addForegroundPermissions(Permission foregroundPermission) { - if (mForegroundPermissions == null) { - mForegroundPermissions = new ArrayList<>(1); - } - mForegroundPermissions.add(foregroundPermission); - } - - /** - * Mark this permission as foreground permission for {@code backgroundPermission}. - * - * @param backgroundPermission The background permission - */ - public void setBackgroundPermission(Permission backgroundPermission) { - mBackgroundPermission = backgroundPermission; - } - - public String getName() { - return mName; - } - - public String getAppOp() { - return mAppOp; - } - - public int getFlags() { - return mFlags; - } - - /** - * Does this permission affect app ops. - * - * <p>I.e. does this permission have a matching app op or is this a background permission. All - * background permissions affect the app op of it's assigned foreground permission. - * - * @return {@code true} if this permission affects app ops - */ - public boolean affectsAppOp() { - return mAppOp != null || isBackgroundPermission(); - } - - public boolean isGranted() { - return mGranted; - } - - public boolean isReviewRequired() { - return (mFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0; - } - - public void resetReviewRequired() { - mFlags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; - } - - public void setGranted(boolean mGranted) { - this.mGranted = mGranted; - } - - public boolean isAppOpAllowed() { - return mAppOpAllowed; - } - - public boolean isUserFixed() { - return (mFlags & PackageManager.FLAG_PERMISSION_USER_FIXED) != 0; - } - - public void setUserFixed(boolean userFixed) { - if (userFixed) { - mFlags |= PackageManager.FLAG_PERMISSION_USER_FIXED; - } else { - mFlags &= ~PackageManager.FLAG_PERMISSION_USER_FIXED; - } - } - - public boolean isSystemFixed() { - return (mFlags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0; - } - - public boolean isPolicyFixed() { - return (mFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0; - } - - public boolean isUserSet() { - return (mFlags & PackageManager.FLAG_PERMISSION_USER_SET) != 0; - } - - public boolean isGrantedByDefault() { - return (mFlags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0; - } - - /** - * If this permission is split into a foreground and background permission, this is the name - * of the background permission. - * - * @return The name of the background permission or {@code null} if the permission is not split - */ - public String getBackgroundPermissionName() { - return mBackgroundPermissionName; - } - - /** - * @return If this permission is split into a foreground and background permission, - * returns the background permission - */ - public Permission getBackgroundPermission() { - return mBackgroundPermission; - } - - /** - * @return If this permission is split into a foreground and background permission, - * returns the foreground permission - */ - public ArrayList<Permission> getForegroundPermissions() { - return mForegroundPermissions; - } - - /** - * @return {@code true} iff this is the foreground permission of a background-foreground-split - * permission - */ - public boolean hasBackgroundPermission() { - return mBackgroundPermissionName != null; - } - - /** - * @return {@code true} iff this is the background permission of a background-foreground-split - * permission - */ - public boolean isBackgroundPermission() { - return mForegroundPermissions != null; - } - - public void setUserSet(boolean userSet) { - if (userSet) { - mFlags |= PackageManager.FLAG_PERMISSION_USER_SET; - } else { - mFlags &= ~PackageManager.FLAG_PERMISSION_USER_SET; - } - } - - public void setPolicyFixed(boolean policyFixed) { - if (policyFixed) { - mFlags |= PackageManager.FLAG_PERMISSION_POLICY_FIXED; - } else { - mFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED; - } - } - - public boolean shouldRevokeOnUpgrade() { - return (mFlags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0; - } - - public void setRevokeOnUpgrade(boolean revokeOnUpgrade) { - if (revokeOnUpgrade) { - mFlags |= PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE; - } else { - mFlags &= ~PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE; - } - } - - public void setAppOpAllowed(boolean mAppOpAllowed) { - this.mAppOpAllowed = mAppOpAllowed; - } - - public boolean isEphemeral() { - return mIsEphemeral; - } - - public boolean isRuntimeOnly() { - return mIsRuntimeOnly; - } - - public boolean isGrantingAllowed(boolean isEphemeralApp, boolean supportsRuntimePermissions) { - return (!isEphemeralApp || isEphemeral()) - && (supportsRuntimePermissions || !isRuntimeOnly()); - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/PermissionApps.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/PermissionApps.java deleted file mode 100644 index d0bf5853b77bb978b640c338bdd418d410a90733..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/PermissionApps.java +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.packageinstaller.permission.model; - -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageItemInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.PermissionInfo; -import android.graphics.drawable.Drawable; -import android.os.AsyncTask; -import android.os.UserHandle; -import android.os.UserManager; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.IconDrawableFactory; -import android.util.Log; -import android.util.SparseArray; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.utils.Utils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class PermissionApps { - private static final String LOG_TAG = "PermissionApps"; - - private final Context mContext; - private final String mGroupName; - private final PackageManager mPm; - private final Callback mCallback; - - private final PmCache mCache; - - private CharSequence mLabel; - private Drawable mIcon; - private List<PermissionApp> mPermApps; - // Map (pkg|uid) -> AppPermission - private ArrayMap<String, PermissionApp> mAppLookup; - - private boolean mSkipUi; - private boolean mRefreshing; - - public PermissionApps(Context context, String groupName, Callback callback) { - this(context, groupName, callback, null); - } - - public PermissionApps(Context context, String groupName, Callback callback, PmCache cache) { - mCache = cache; - mContext = context; - mPm = mContext.getPackageManager(); - mGroupName = groupName; - mCallback = callback; - loadGroupInfo(); - } - - public String getGroupName() { - return mGroupName; - } - - public void loadNowWithoutUi() { - mSkipUi = true; - createMap(loadPermissionApps()); - } - - /** - * Start an async refresh and call back the registered call back once done. - * - * @param getUiInfo If the UI info should be updated - */ - public void refresh(boolean getUiInfo) { - if (mCallback == null) { - throw new IllegalStateException("callback needs to be set"); - } - - if (!mRefreshing) { - mRefreshing = true; - mSkipUi = !getUiInfo; - new PermissionAppsLoader().execute(); - } - } - - /** - * Refresh the state and do not return until it finishes. Should not be called while an {@link - * #refresh async referesh} is in progress. - */ - public void refreshSync() { - mSkipUi = true; - createMap(loadPermissionApps()); - } - - public int getGrantedCount(ArraySet<String> launcherPkgs) { - int count = 0; - for (PermissionApp app : mPermApps) { - if (!Utils.shouldShowPermission(app.getPermissionGroup())) { - continue; - } - if (Utils.isSystem(app, launcherPkgs)) { - // We default to not showing system apps, so hide them from count. - continue; - } - if (app.areRuntimePermissionsGranted()) { - count++; - } - } - return count; - } - - public int getTotalCount(ArraySet<String> launcherPkgs) { - int count = 0; - for (PermissionApp app : mPermApps) { - if (!Utils.shouldShowPermission(app.getPermissionGroup())) { - continue; - } - if (Utils.isSystem(app, launcherPkgs)) { - // We default to not showing system apps, so hide them from count. - continue; - } - count++; - } - return count; - } - - public List<PermissionApp> getApps() { - return mPermApps; - } - - public PermissionApp getApp(String key) { - return mAppLookup.get(key); - } - - public CharSequence getLabel() { - return mLabel; - } - - public Drawable getIcon() { - return mIcon; - } - - private List<PermissionApp> loadPermissionApps() { - PackageItemInfo groupInfo = getGroupInfo(mGroupName); - if (groupInfo == null) { - return Collections.emptyList(); - } - - List<PermissionInfo> groupPermInfos = getGroupPermissionInfos(mGroupName); - if (groupPermInfos == null) { - return Collections.emptyList(); - } - - ArrayList<PermissionApp> permApps = new ArrayList<>(); - IconDrawableFactory iconFactory = IconDrawableFactory.newInstance(mContext); - - UserManager userManager = mContext.getSystemService(UserManager.class); - for (UserHandle user : userManager.getUserProfiles()) { - List<PackageInfo> apps = mCache != null ? mCache.getPackages(user.getIdentifier()) - : mPm.getInstalledPackagesAsUser(PackageManager.GET_PERMISSIONS, - user.getIdentifier()); - - final int N = apps.size(); - for (int i = 0; i < N; i++) { - PackageInfo app = apps.get(i); - if (app.requestedPermissions == null) { - continue; - } - - for (int j = 0; j < app.requestedPermissions.length; j++) { - String requestedPerm = app.requestedPermissions[j]; - - PermissionInfo requestedPermissionInfo = null; - - for (PermissionInfo groupPermInfo : groupPermInfos) { - if (requestedPerm.equals(groupPermInfo.name)) { - requestedPermissionInfo = groupPermInfo; - break; - } - } - - if (requestedPermissionInfo == null) { - continue; - } - - if ((requestedPermissionInfo.protectionLevel - & PermissionInfo.PROTECTION_MASK_BASE) - != PermissionInfo.PROTECTION_DANGEROUS - || (requestedPermissionInfo.flags - & PermissionInfo.FLAG_INSTALLED) == 0 - || (requestedPermissionInfo.flags - & PermissionInfo.FLAG_REMOVED) != 0) { - continue; - } - - AppPermissionGroup group = AppPermissionGroup.create(mContext, - app, groupInfo, groupPermInfos, user); - - if (group == null) { - continue; - } - - String label = mSkipUi ? app.packageName - : app.applicationInfo.loadLabel(mPm).toString(); - - Drawable icon = null; - if (!mSkipUi) { - icon = iconFactory.getBadgedIcon(app.applicationInfo, - UserHandle.getUserId(group.getApp().applicationInfo.uid)); - } - - PermissionApp permApp = new PermissionApp(app.packageName, group, label, icon, - app.applicationInfo); - - permApps.add(permApp); - break; // move to the next app. - } - } - } - - Collections.sort(permApps); - - return permApps; - } - - private void createMap(List<PermissionApp> result) { - mAppLookup = new ArrayMap<>(); - for (PermissionApp app : result) { - mAppLookup.put(app.getKey(), app); - } - mPermApps = result; - } - - private PackageItemInfo getGroupInfo(String groupName) { - try { - return mContext.getPackageManager().getPermissionGroupInfo(groupName, 0); - } catch (NameNotFoundException e) { - /* ignore */ - } - try { - return mContext.getPackageManager().getPermissionInfo(groupName, 0); - } catch (NameNotFoundException e2) { - /* ignore */ - } - return null; - } - - private List<PermissionInfo> getGroupPermissionInfos(String groupName) { - try { - return mContext.getPackageManager().queryPermissionsByGroup(groupName, 0); - } catch (NameNotFoundException e) { - /* ignore */ - } - try { - PermissionInfo permissionInfo = mContext.getPackageManager() - .getPermissionInfo(groupName, 0); - List<PermissionInfo> permissions = new ArrayList<>(); - permissions.add(permissionInfo); - return permissions; - } catch (NameNotFoundException e2) { - /* ignore */ - } - return null; - } - - private void loadGroupInfo() { - PackageItemInfo info; - try { - info = mPm.getPermissionGroupInfo(mGroupName, 0); - } catch (PackageManager.NameNotFoundException e) { - try { - PermissionInfo permInfo = mPm.getPermissionInfo(mGroupName, 0); - if ((permInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) - != PermissionInfo.PROTECTION_DANGEROUS) { - Log.w(LOG_TAG, mGroupName + " is not a runtime permission"); - return; - } - info = permInfo; - } catch (NameNotFoundException reallyNotFound) { - Log.w(LOG_TAG, "Can't find permission: " + mGroupName, reallyNotFound); - return; - } - } - mLabel = info.loadLabel(mPm); - if (info.icon != 0) { - mIcon = info.loadUnbadgedIcon(mPm); - } else { - mIcon = mContext.getDrawable(R.drawable.ic_perm_device_info); - } - mIcon = Utils.applyTint(mContext, mIcon, android.R.attr.colorControlNormal); - } - - public static class PermissionApp implements Comparable<PermissionApp> { - private final String mPackageName; - private final AppPermissionGroup mAppPermissionGroup; - private final String mLabel; - private final Drawable mIcon; - private final ApplicationInfo mInfo; - - public PermissionApp(String packageName, AppPermissionGroup appPermissionGroup, - String label, Drawable icon, ApplicationInfo info) { - mPackageName = packageName; - mAppPermissionGroup = appPermissionGroup; - mLabel = label; - mIcon = icon; - mInfo = info; - } - - public ApplicationInfo getAppInfo() { - return mInfo; - } - - public String getKey() { - return mPackageName + getUid(); - } - - public String getLabel() { - return mLabel; - } - - public Drawable getIcon() { - return mIcon; - } - - public boolean areRuntimePermissionsGranted() { - return mAppPermissionGroup.areRuntimePermissionsGranted(); - } - - public boolean isReviewRequired() { - return mAppPermissionGroup.isReviewRequired(); - } - - public void grantRuntimePermissions() { - mAppPermissionGroup.grantRuntimePermissions(false); - } - - public void revokeRuntimePermissions() { - mAppPermissionGroup.revokeRuntimePermissions(false); - } - - public boolean isPolicyFixed() { - return mAppPermissionGroup.isPolicyFixed(); - } - - public boolean isSystemFixed() { - return mAppPermissionGroup.isSystemFixed(); - } - - public boolean hasGrantedByDefaultPermissions() { - return mAppPermissionGroup.hasGrantedByDefaultPermission(); - } - - public boolean doesSupportRuntimePermissions() { - return mAppPermissionGroup.doesSupportRuntimePermissions(); - } - - public int getUserId() { - return mAppPermissionGroup.getUserId(); - } - - public String getPackageName() { - return mPackageName; - } - - public AppPermissionGroup getPermissionGroup() { - return mAppPermissionGroup; - } - - @Override - public int compareTo(PermissionApp another) { - final int result = mLabel.compareTo(another.mLabel); - if (result == 0) { - // Unbadged before badged. - return getKey().compareTo(another.getKey()); - } - return result; - } - - public int getUid() { - return mAppPermissionGroup.getApp().applicationInfo.uid; - } - } - - private class PermissionAppsLoader extends AsyncTask<Void, Void, List<PermissionApp>> { - - @Override - protected List<PermissionApp> doInBackground(Void... args) { - return loadPermissionApps(); - } - - @Override - protected void onPostExecute(List<PermissionApp> result) { - mRefreshing = false; - createMap(result); - if (mCallback != null) { - mCallback.onPermissionsLoaded(PermissionApps.this); - } - } - } - - /** - * Class used to reduce the number of calls to the package manager. - * This caches app information so it should only be used across parallel PermissionApps - * instances, and should not be retained across UI refresh. - */ - public static class PmCache { - private final SparseArray<List<PackageInfo>> mPackageInfoCache = new SparseArray<>(); - private final PackageManager mPm; - - public PmCache(PackageManager pm) { - mPm = pm; - } - - public synchronized List<PackageInfo> getPackages(int userId) { - List<PackageInfo> ret = mPackageInfoCache.get(userId); - if (ret == null) { - ret = mPm.getInstalledPackagesAsUser(PackageManager.GET_PERMISSIONS, userId); - mPackageInfoCache.put(userId, ret); - } - return ret; - } - } - - public interface Callback { - void onPermissionsLoaded(PermissionApps permissionApps); - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/PermissionGroup.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/PermissionGroup.java deleted file mode 100644 index ebef732f1d5977a5111fe223f5260ab811bace80..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/PermissionGroup.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.model; - -import android.graphics.drawable.Drawable; - -/** - * A permission group with runtime permission as defined in an app's manifest as - * {@code android:permission-group}. - * - * <p>For individual permissions that are not part of any group a {@link PermissionGroup} is created - * dynamically with the name and icon of the individual permission. - */ -public final class PermissionGroup implements Comparable<PermissionGroup> { - private final String mName; - private final String mDeclaringPackage; - private final CharSequence mLabel; - private final Drawable mIcon; - private final int mTotal; - private final int mGranted; - - PermissionGroup(String name, String declaringPackage, CharSequence label, Drawable icon, - int total, int granted) { - mDeclaringPackage = declaringPackage; - mName = name; - mLabel = label; - mIcon = icon; - mTotal = total; - mGranted = granted; - } - - public String getName() { - return mName; - } - - public String getDeclaringPackage() { - return mDeclaringPackage; - } - - public CharSequence getLabel() { - return mLabel; - } - - public Drawable getIcon() { - return mIcon; - } - - /** - * @return The number of apps that might request permissions of this group - */ - public int getTotal() { - return mTotal; - } - - /** - * @return The number of apps that were granted permissions of this group - */ - public int getGranted() { - return mGranted; - } - - @Override - public int compareTo(PermissionGroup another) { - return mLabel.toString().compareTo(another.mLabel.toString()); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (obj == null) { - return false; - } - - if (getClass() != obj.getClass()) { - return false; - } - - PermissionGroup other = (PermissionGroup) obj; - - if (mName == null) { - if (other.mName != null) { - return false; - } - } else if (!mName.equals(other.mName)) { - return false; - } - - if (mTotal != other.mTotal) { - return false; - } - - if (mGranted != other.mGranted) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - return mName != null ? mName.hashCode() + mTotal + mGranted : mTotal + mGranted; - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/PermissionGroups.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/PermissionGroups.java deleted file mode 100644 index 491b059909f131113e124bb1f3747db1fd989558..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/model/PermissionGroups.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.model; - -import static android.content.pm.PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE; -import static android.content.pm.PackageItemInfo.SAFE_LABEL_FLAG_TRIM; - -import android.app.LoaderManager; -import android.app.LoaderManager.LoaderCallbacks; -import android.content.AsyncTaskLoader; -import android.content.Context; -import android.content.Loader; -import android.content.pm.PackageInfo; -import android.content.pm.PackageItemInfo; -import android.content.pm.PackageManager; -import android.content.pm.PermissionGroupInfo; -import android.content.pm.PermissionInfo; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.util.ArraySet; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.utils.Utils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -/** - * All {@link PermissionGroup permission groups} defined by any app. - */ -public final class PermissionGroups implements LoaderCallbacks<List<PermissionGroup>> { - private final ArrayList<PermissionGroup> mGroups = new ArrayList<>(); - private final Context mContext; - private final LoaderManager mLoaderManager; - private final PermissionsGroupsChangeCallback mCallback; - - public interface PermissionsGroupsChangeCallback { - public void onPermissionGroupsChanged(); - } - - public PermissionGroups(Context context, LoaderManager loaderManager, - PermissionsGroupsChangeCallback callback) { - mContext = context; - mLoaderManager = loaderManager; - mCallback = callback; - mLoaderManager.initLoader(0, null, this); - } - - @Override - public Loader<List<PermissionGroup>> onCreateLoader(int id, Bundle args) { - return new PermissionsLoader(mContext); - } - - @Override - public void onLoadFinished(Loader<List<PermissionGroup>> loader, - List<PermissionGroup> groups) { - if (mGroups.equals(groups)) { - return; - } - mGroups.clear(); - mGroups.addAll(groups); - mCallback.onPermissionGroupsChanged(); - } - - @Override - public void onLoaderReset(Loader<List<PermissionGroup>> loader) { - mGroups.clear(); - mCallback.onPermissionGroupsChanged(); - } - - public List<PermissionGroup> getGroups() { - return mGroups; - } - - public PermissionGroup getGroup(String name) { - for (PermissionGroup group : mGroups) { - if (group.getName().equals(name)) { - return group; - } - } - return null; - } - - private static final class PermissionsLoader extends AsyncTaskLoader<List<PermissionGroup>> - implements PackageManager.OnPermissionsChangedListener { - - public PermissionsLoader(Context context) { - super(context); - } - - @Override - protected void onStartLoading() { - getContext().getPackageManager().addOnPermissionsChangeListener(this); - forceLoad(); - } - - @Override - protected void onStopLoading() { - getContext().getPackageManager().removeOnPermissionsChangeListener(this); - } - - @Override - public List<PermissionGroup> loadInBackground() { - ArraySet<String> launcherPkgs = Utils.getLauncherPackages(getContext()); - PermissionApps.PmCache pmCache = new PermissionApps.PmCache( - getContext().getPackageManager()); - - List<PermissionGroup> groups = new ArrayList<>(); - Set<String> seenPermissions = new ArraySet<>(); - - PackageManager packageManager = getContext().getPackageManager(); - List<PermissionGroupInfo> groupInfos = packageManager.getAllPermissionGroups(0); - - for (PermissionGroupInfo groupInfo : groupInfos) { - // Mare sure we respond to cancellation. - if (isLoadInBackgroundCanceled()) { - return Collections.emptyList(); - } - - // Get the permissions in this group. - final List<PermissionInfo> groupPermissions; - try { - groupPermissions = packageManager.queryPermissionsByGroup(groupInfo.name, 0); - } catch (PackageManager.NameNotFoundException e) { - continue; - } - - boolean hasRuntimePermissions = false; - - // Cache seen permissions and see if group has runtime permissions. - for (PermissionInfo groupPermission : groupPermissions) { - seenPermissions.add(groupPermission.name); - if ((groupPermission.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) - == PermissionInfo.PROTECTION_DANGEROUS - && (groupPermission.flags & PermissionInfo.FLAG_INSTALLED) != 0 - && (groupPermission.flags & PermissionInfo.FLAG_REMOVED) == 0) { - hasRuntimePermissions = true; - } - } - - // No runtime permissions - not interesting for us. - if (!hasRuntimePermissions) { - continue; - } - - CharSequence label = loadItemInfoLabel(groupInfo); - Drawable icon = loadItemInfoIcon(groupInfo); - - PermissionApps permApps = new PermissionApps(getContext(), groupInfo.name, null, - pmCache); - permApps.refreshSync(); - - // Create the group and add to the list. - PermissionGroup group = new PermissionGroup(groupInfo.name, - groupInfo.packageName, label, icon, permApps.getTotalCount(launcherPkgs), - permApps.getGrantedCount(launcherPkgs)); - groups.add(group); - } - - - // Make sure we add groups for lone runtime permissions. - List<PackageInfo> installedPackages = getContext().getPackageManager() - .getInstalledPackages(PackageManager.GET_PERMISSIONS); - - - // We will filter out permissions that no package requests. - Set<String> requestedPermissions = new ArraySet<>(); - for (PackageInfo installedPackage : installedPackages) { - if (installedPackage.requestedPermissions == null) { - continue; - } - for (String requestedPermission : installedPackage.requestedPermissions) { - requestedPermissions.add(requestedPermission); - } - } - - for (PackageInfo installedPackage : installedPackages) { - if (installedPackage.permissions == null) { - continue; - } - - for (PermissionInfo permissionInfo : installedPackage.permissions) { - // If we have handled this permission, no more work to do. - if (!seenPermissions.add(permissionInfo.name)) { - continue; - } - - // We care only about installed runtime permissions. - if ((permissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) - != PermissionInfo.PROTECTION_DANGEROUS - || (permissionInfo.flags & PermissionInfo.FLAG_INSTALLED) == 0) { - continue; - } - - // If no app uses this permission, - if (!requestedPermissions.contains(permissionInfo.name)) { - continue; - } - - CharSequence label = loadItemInfoLabel(permissionInfo); - Drawable icon = loadItemInfoIcon(permissionInfo); - - PermissionApps permApps = new PermissionApps(getContext(), permissionInfo.name, - null, pmCache); - permApps.refreshSync(); - - // Create the group and add to the list. - PermissionGroup group = new PermissionGroup(permissionInfo.name, - permissionInfo.packageName, label, icon, - permApps.getTotalCount(launcherPkgs), - permApps.getGrantedCount(launcherPkgs)); - groups.add(group); - } - } - - Collections.sort(groups); - return groups; - } - - private CharSequence loadItemInfoLabel(PackageItemInfo itemInfo) { - CharSequence label = itemInfo.loadSafeLabel(getContext().getPackageManager(), 0, - SAFE_LABEL_FLAG_FIRST_LINE | SAFE_LABEL_FLAG_TRIM); - if (label == null) { - label = itemInfo.name; - } - return label; - } - - private Drawable loadItemInfoIcon(PackageItemInfo itemInfo) { - Drawable icon = null; - if (itemInfo.icon > 0) { - icon = Utils.loadDrawable(getContext().getPackageManager(), - itemInfo.packageName, itemInfo.icon); - } - if (icon == null) { - icon = getContext().getDrawable(R.drawable.ic_perm_device_info); - } - return icon; - } - - @Override - public void onPermissionsChanged(int uid) { - forceLoad(); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/service/RuntimePermissionPresenterServiceImpl.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/service/RuntimePermissionPresenterServiceImpl.java deleted file mode 100644 index ab19fa11a613610168e1f5569dbf431926acfb90..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/service/RuntimePermissionPresenterServiceImpl.java +++ /dev/null @@ -1,84 +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.service; - -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.permission.RuntimePermissionPresentationInfo; -import android.permissionpresenterservice.RuntimePermissionPresenterService; -import android.util.Log; - -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.AppPermissions; -import com.android.packageinstaller.permission.utils.Utils; - -import java.util.ArrayList; -import java.util.List; - -/** - * Service that provides presentation information for runtime permissions. - */ -public final class RuntimePermissionPresenterServiceImpl extends RuntimePermissionPresenterService { - private static final String LOG_TAG = "PermissionPresenter"; - - @Override - public List<RuntimePermissionPresentationInfo> onGetAppPermissions(String packageName) { - final PackageInfo packageInfo; - try { - packageInfo = getPackageManager().getPackageInfo(packageName, - PackageManager.GET_PERMISSIONS); - } catch (PackageManager.NameNotFoundException e) { - Log.e(LOG_TAG, "Error getting package:" + packageName, e); - return null; - } - - List<RuntimePermissionPresentationInfo> permissions = new ArrayList<>(); - - AppPermissions appPermissions = new AppPermissions(this, packageInfo, false, null); - for (AppPermissionGroup group : appPermissions.getPermissionGroups()) { - if (Utils.shouldShowPermission(group)) { - final boolean granted = group.areRuntimePermissionsGranted(); - final boolean standard = Utils.OS_PKG.equals(group.getDeclaringPackage()); - RuntimePermissionPresentationInfo permission = - new RuntimePermissionPresentationInfo(group.getLabel(), - granted, standard); - permissions.add(permission); - } - } - - return permissions; - } - - @Override - public void onRevokeRuntimePermission(String packageName, String permissionName) { - try { - final PackageInfo packageInfo = getPackageManager().getPackageInfo(packageName, - PackageManager.GET_PERMISSIONS); - final AppPermissions appPermissions = new AppPermissions(this, packageInfo, false, - null); - - final AppPermissionGroup appPermissionGroup = appPermissions.getGroupForPermission( - permissionName); - - if (appPermissionGroup != null) { - appPermissionGroup.revokeRuntimePermissions(false); - } - } catch (PackageManager.NameNotFoundException e) { - Log.e(LOG_TAG, "Error getting package:" + packageName, e); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ButtonBarLayout.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ButtonBarLayout.java deleted file mode 100644 index 8b0f219b9bf4406dbb68fe1750bbe7e67f2a622f..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ButtonBarLayout.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.Gravity; -import android.view.View; -import android.widget.LinearLayout; - -import com.android.packageinstaller.R; - -/** - * An extension of LinearLayout that automatically switches to vertical - * orientation when it can't fit its child views horizontally. - */ -public class ButtonBarLayout extends LinearLayout { - /** Whether the current configuration allows stacking. */ - private boolean mAllowStacking; - - private int mLastWidthSize = -1; - - public ButtonBarLayout(Context context, AttributeSet attrs) { - super(context, attrs); - mAllowStacking = true; - } - - public void setAllowStacking(boolean allowStacking) { - if (mAllowStacking != allowStacking) { - mAllowStacking = allowStacking; - if (!mAllowStacking && getOrientation() == LinearLayout.VERTICAL) { - setStacked(false); - } - requestLayout(); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - final int widthSize = MeasureSpec.getSize(widthMeasureSpec); - - if (mAllowStacking) { - if (widthSize > mLastWidthSize && isStacked()) { - // We're being measured wider this time, try un-stacking. - setStacked(false); - } - - mLastWidthSize = widthSize; - } - - boolean needsRemeasure = false; - - // If we're not stacked, make sure the measure spec is AT_MOST rather - // than EXACTLY. This ensures that we'll still get TOO_SMALL so that we - // know to stack the buttons. - final int initialWidthMeasureSpec; - if (!isStacked() && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) { - initialWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST); - - // We'll need to remeasure again to fill excess space. - needsRemeasure = true; - } else { - initialWidthMeasureSpec = widthMeasureSpec; - } - - super.onMeasure(initialWidthMeasureSpec, heightMeasureSpec); - - if (mAllowStacking && !isStacked()) { - final int measuredWidth = getMeasuredWidthAndState(); - final int measuredWidthState = measuredWidth & MEASURED_STATE_MASK; - if (measuredWidthState == MEASURED_STATE_TOO_SMALL) { - setStacked(true); - - // Measure again in the new orientation. - needsRemeasure = true; - } - } - - if (needsRemeasure) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - } - - private void setStacked(boolean stacked) { - setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL); - setGravity(stacked ? Gravity.END : Gravity.BOTTOM); - - final View spacer = findViewById(R.id.spacer); - if (spacer != null) { - spacer.setVisibility(stacked ? View.GONE : View.INVISIBLE); - } - } - - private boolean isStacked() { - return getOrientation() == LinearLayout.VERTICAL; - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ConfirmActionDialogFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ConfirmActionDialogFragment.java deleted file mode 100644 index c13f63098230ef7cc67d120ac7ee8275ead47148..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ConfirmActionDialogFragment.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.os.Bundle; - -import androidx.fragment.app.DialogFragment; - -import com.android.packageinstaller.R; - -public final class ConfirmActionDialogFragment extends DialogFragment { - public static final String ARG_MESSAGE = "MESSAGE"; - public static final String ARG_ACTION = "ACTION"; - - public interface OnActionConfirmedListener { - void onActionConfirmed(String action); - } - - public static ConfirmActionDialogFragment newInstance(CharSequence message, String action) { - Bundle arguments = new Bundle(); - arguments.putCharSequence(ARG_MESSAGE, message); - arguments.putString(ARG_ACTION, action); - ConfirmActionDialogFragment fragment = new ConfirmActionDialogFragment(); - fragment.setArguments(arguments); - return fragment; - } - - @Override - public Dialog onCreateDialog(Bundle bundle) { - return new AlertDialog.Builder(getContext()) - .setMessage(getArguments().getString(ARG_MESSAGE)) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.grant_dialog_button_deny_anyway, - (dialog, which) -> { - Activity activity = getActivity(); - if (activity instanceof OnActionConfirmedListener) { - String groupName = getArguments().getString(ARG_ACTION); - ((OnActionConfirmedListener) activity) - .onActionConfirmed(groupName); - } - }) - .create(); - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java deleted file mode 100644 index 51bd2836a282206e6a92f295bdb1b59952430001..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java +++ /dev/null @@ -1,834 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui; - -import static android.content.pm.PackageManager.PERMISSION_DENIED; - -import static com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler.DENIED; -import static com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler - .DENIED_DO_NOT_ASK_AGAIN; -import static com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler.GRANTED_ALWAYS; -import static com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler - .GRANTED_FOREGROUND_ONLY; -import static com.android.packageinstaller.permission.utils.Utils.getRequestMessage; - -import android.app.admin.DevicePolicyManager; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.PackageParser; -import android.content.res.Resources; -import android.graphics.drawable.Icon; -import android.os.Build; -import android.os.Bundle; -import android.text.Html; -import android.text.Spanned; -import android.util.ArrayMap; -import android.util.Log; -import android.util.Pair; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; - -import com.android.internal.content.PackageMonitor; -import com.android.internal.logging.nano.MetricsProto; -import com.android.packageinstaller.DeviceUtils; -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.AppPermissions; -import com.android.packageinstaller.permission.model.Permission; -import com.android.packageinstaller.permission.ui.auto.GrantPermissionsAutoViewHandler; -import com.android.packageinstaller.permission.utils.ArrayUtils; -import com.android.packageinstaller.permission.utils.EventLogger; -import com.android.packageinstaller.permission.utils.SafetyNetLogger; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class GrantPermissionsActivity extends OverlayTouchActivity - implements GrantPermissionsViewHandler.ResultListener { - - private static final String LOG_TAG = "GrantPermissionsActivity"; - - private String[] mRequestedPermissions; - - private ArrayMap<Pair<String, Boolean>, GroupState> mRequestGrantPermissionGroups = - new ArrayMap<>(); - - private GrantPermissionsViewHandler mViewHandler; - private AppPermissions mAppPermissions; - - boolean mResultSet; - - private PackageManager.OnPermissionsChangedListener mPermissionChangeListener; - private PackageMonitor mPackageMonitor; - - private String mCallingPackage; - - private int getPermissionPolicy() { - DevicePolicyManager devicePolicyManager = getSystemService(DevicePolicyManager.class); - return devicePolicyManager.getPermissionPolicy(null); - } - - /** - * Try to add a single permission that is requested to be granted. - * - * <p>This does <u>not</u> expand the permissions into the {@link #computeAffectedPermissions - * affected permissions}. - * - * @param group The group the permission belongs to (might be a background permission group) - * @param permission The permission to add - * @param isFirstInstance Is this the first time the groupStates get created - */ - private void addRequestedPermissions(AppPermissionGroup group, String permission, - boolean isFirstInstance) { - if (!group.isGrantingAllowed()) { - // Skip showing groups that we know cannot be granted. - return; - } - - // We allow the user to choose only non-fixed permissions. A permission - // is fixed either by device policy or the user denying with prejudice. - if (!group.isUserFixed() && !group.isPolicyFixed()) { - Pair<String, Boolean> groupKey = new Pair<>(group.getName(), - group.isBackgroundGroup()); - - GroupState state = mRequestGrantPermissionGroups.get(groupKey); - if (state == null) { - state = new GroupState(group); - mRequestGrantPermissionGroups.put(groupKey, state); - } - state.affectedPermissions = ArrayUtils.appendString( - state.affectedPermissions, permission); - - boolean skipGroup = false; - switch (getPermissionPolicy()) { - case DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT: { - if (!group.areRuntimePermissionsGranted()) { - group.grantRuntimePermissions(false, new String[]{permission}); - } - state.mState = GroupState.STATE_ALLOWED; - group.setPolicyFixed(); - skipGroup = true; - } break; - - case DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY: { - if (group.areRuntimePermissionsGranted()) { - group.revokeRuntimePermissions(false, new String[]{permission}); - } - state.mState = GroupState.STATE_DENIED; - group.setPolicyFixed(); - skipGroup = true; - } break; - - default: { - if (group.areRuntimePermissionsGranted()) { - group.grantRuntimePermissions(false, new String[]{permission}); - state.mState = GroupState.STATE_ALLOWED; - skipGroup = true; - } - } break; - } - - if (skipGroup && isFirstInstance) { - // Only allow to skip groups when this is the first time the dialog was created. - // Otherwise the number of groups changes between instances of the dialog. - state.mState = GroupState.STATE_SKIPPED; - } - } - } - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Cache this as this can only read on onCreate, not later. - mCallingPackage = getCallingPackage(); - - mPackageMonitor = new PackageMonitor() { - @Override - public void onPackageRemoved(String packageName, int uid) { - if (mCallingPackage.equals(packageName)) { - Log.w(LOG_TAG, mCallingPackage + " was uninstalled"); - - finish(); - } - } - }; - - setFinishOnTouchOutside(false); - - getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); - - setTitle(R.string.permission_request_title); - - if (DeviceUtils.isTelevision(this)) { - mViewHandler = new com.android.packageinstaller.permission.ui.television - .GrantPermissionsViewHandlerImpl(this, - mCallingPackage).setResultListener(this); - } else if (DeviceUtils.isWear(this)) { - mViewHandler = new GrantPermissionsWatchViewHandler(this).setResultListener(this); - } else if (DeviceUtils.isAuto(this)) { - mViewHandler = new GrantPermissionsAutoViewHandler(this, mCallingPackage) - .setResultListener(this); - } else { - mViewHandler = new com.android.packageinstaller.permission.ui.handheld - .GrantPermissionsViewHandlerImpl(this, mCallingPackage) - .setResultListener(this); - } - - mRequestedPermissions = getIntent().getStringArrayExtra( - PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES); - if (mRequestedPermissions == null) { - mRequestedPermissions = new String[0]; - } - - final int requestedPermCount = mRequestedPermissions.length; - - if (requestedPermCount == 0) { - setResultAndFinish(); - return; - } - - try { - mPermissionChangeListener = new PermissionChangeListener(); - } catch (NameNotFoundException e) { - setResultAndFinish(); - return; - } - - PackageInfo callingPackageInfo = getCallingPackageInfo(); - - if (callingPackageInfo == null || callingPackageInfo.requestedPermissions == null - || callingPackageInfo.requestedPermissions.length <= 0) { - setResultAndFinish(); - return; - } - - // Don't allow legacy apps to request runtime permissions. - if (callingPackageInfo.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { - // Returning empty arrays means a cancellation. - mRequestedPermissions = new String[0]; - setResultAndFinish(); - return; - } - - mAppPermissions = new AppPermissions(this, callingPackageInfo, false, - new Runnable() { - @Override - public void run() { - setResultAndFinish(); - } - }); - - for (String requestedPermission : mRequestedPermissions) { - if (requestedPermission == null) { - continue; - } - - ArrayList<String> affectedPermissions = - computeAffectedPermissions(requestedPermission); - - int numAffectedPermissions = affectedPermissions.size(); - for (int i = 0; i < numAffectedPermissions; i++) { - AppPermissionGroup group = - mAppPermissions.getGroupForPermission(affectedPermissions.get(i)); - if (group == null) { - continue; - } - - addRequestedPermissions(group, affectedPermissions.get(i), icicle == null); - } - } - - int numGroupStates = mRequestGrantPermissionGroups.size(); - for (int groupStateNum = 0; groupStateNum < numGroupStates; groupStateNum++) { - GroupState groupState = mRequestGrantPermissionGroups.valueAt(groupStateNum); - AppPermissionGroup group = groupState.mGroup; - - // Restore permission group state after lifecycle events - if (icicle != null) { - groupState.mState = icicle.getInt( - getInstanceStateKey(mRequestGrantPermissionGroups.keyAt(groupStateNum)), - groupState.mState); - } - - // Do not attempt to grant background access if foreground access is not either already - // granted or requested - if (group.isBackgroundGroup()) { - // Check if a foreground permission is already granted - boolean foregroundGroupAlreadyGranted = mAppPermissions.getPermissionGroup( - group.getName()).areRuntimePermissionsGranted(); - boolean hasForegroundRequest = (getForegroundGroupState(group.getName()) != null); - - if (!foregroundGroupAlreadyGranted && !hasForegroundRequest) { - // The background permission cannot be granted at this time - int numPermissions = groupState.affectedPermissions.length; - for (int permissionNum = 0; permissionNum < numPermissions; permissionNum++) { - Log.w(LOG_TAG, - "Cannot grant " + groupState.affectedPermissions[permissionNum] - + " as the matching foreground permission is not already " - + "granted."); - } - - groupState.mState = GroupState.STATE_SKIPPED; - } - } - } - - setContentView(mViewHandler.createView()); - - Window window = getWindow(); - WindowManager.LayoutParams layoutParams = window.getAttributes(); - mViewHandler.updateWindowAttributes(layoutParams); - window.setAttributes(layoutParams); - - // Restore UI state after lifecycle events. This has to be before - // showNextPermissionGroupGrantRequest is called. showNextPermissionGroupGrantRequest might - // update the UI and the UI behaves differently for updates and initial creations. - if (icicle != null) { - mViewHandler.loadInstanceState(icicle); - } - - if (!showNextPermissionGroupGrantRequest()) { - setResultAndFinish(); - } else if (icicle == null) { - int numRequestedPermissions = mRequestedPermissions.length; - for (int permissionNum = 0; permissionNum < numRequestedPermissions; permissionNum++) { - String permission = mRequestedPermissions[permissionNum]; - - EventLogger.logPermission( - MetricsProto.MetricsEvent.ACTION_PERMISSION_REQUESTED, permission, - mAppPermissions.getPackageInfo().packageName); - } - } - } - - /** - * Update the {@link #mRequestedPermissions} if the system reports them as granted. - * - * <p>This also updates the {@link #mAppPermissions} state and switches to the next group grant - * request if the current group becomes granted. - */ - private void updateIfPermissionsWereGranted() { - PackageManager pm = getPackageManager(); - - boolean mightShowNextGroup = true; - int numGroupStates = mRequestGrantPermissionGroups.size(); - for (int i = 0; i < numGroupStates; i++) { - GroupState groupState = mRequestGrantPermissionGroups.valueAt(i); - - if (groupState == null || groupState.mState != GroupState.STATE_UNKNOWN) { - // Group has already been approved / denied via the UI by the user - continue; - } - - boolean allAffectedPermissionsOfThisGroupAreGranted = true; - - if (groupState.affectedPermissions == null) { - // It is not clear which permissions belong to this group, hence never skip this - // view - allAffectedPermissionsOfThisGroupAreGranted = false; - } else { - for (int permNum = 0; permNum < groupState.affectedPermissions.length; - permNum++) { - if (pm.checkPermission(groupState.affectedPermissions[permNum], mCallingPackage) - == PERMISSION_DENIED) { - allAffectedPermissionsOfThisGroupAreGranted = false; - break; - } - } - } - - if (allAffectedPermissionsOfThisGroupAreGranted) { - groupState.mState = GroupState.STATE_ALLOWED; - - if (mightShowNextGroup) { - // The UI currently displays the first group with - // mState == STATE_UNKNOWN. So we are switching to next group until we - // could not allow a group that was still unknown - if (!showNextPermissionGroupGrantRequest()) { - setResultAndFinish(); - } - } - } else { - mightShowNextGroup = false; - } - } - } - - @Override - protected void onStart() { - super.onStart(); - - PackageManager pm = getPackageManager(); - pm.addOnPermissionsChangeListener(mPermissionChangeListener); - - // get notified when the package is removed - mPackageMonitor.register(this, getMainLooper(), false); - - // check if the package was removed while this activity was not started - try { - pm.getPackageInfo(mCallingPackage, 0); - } catch (NameNotFoundException e) { - Log.w(LOG_TAG, mCallingPackage + " was uninstalled while this activity was stopped", e); - finish(); - } - - updateIfPermissionsWereGranted(); - } - - @Override - protected void onStop() { - super.onStop(); - - mPackageMonitor.unregister(); - - getPackageManager().removeOnPermissionsChangeListener(mPermissionChangeListener); - } - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - View rootView = getWindow().getDecorView(); - if (rootView.getTop() != 0) { - // We are animating the top view, need to compensate for that in motion events. - ev.setLocation(ev.getX(), ev.getY() - rootView.getTop()); - } - return super.dispatchTouchEvent(ev); - } - - /** - * Compose a key that stores the GroupState.mState in the instance state. - * - * @param requestGrantPermissionGroupsKey The key of the permission group - * - * @return A unique key to be used in the instance state - */ - private static String getInstanceStateKey( - Pair<String, Boolean> requestGrantPermissionGroupsKey) { - return GrantPermissionsActivity.class.getName() + "_" - + requestGrantPermissionGroupsKey.first + "_" - + requestGrantPermissionGroupsKey.second; - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - mViewHandler.saveInstanceState(outState); - - int numGroups = mRequestGrantPermissionGroups.size(); - for (int i = 0; i < numGroups; i++) { - int state = mRequestGrantPermissionGroups.valueAt(i).mState; - - if (state != GroupState.STATE_UNKNOWN) { - outState.putInt(getInstanceStateKey(mRequestGrantPermissionGroups.keyAt(i)), state); - } - } - } - - /** - * @return the background group state for the permission group with the {@code name} - */ - private GroupState getBackgroundGroupState(String name) { - return mRequestGrantPermissionGroups.get(new Pair<>(name, true)); - } - - /** - * @return the foreground group state for the permission group with the {@code name} - */ - private GroupState getForegroundGroupState(String name) { - return mRequestGrantPermissionGroups.get(new Pair<>(name, false)); - } - - private boolean shouldShowRequestForGroupState(GroupState groupState) { - if (groupState.mState == GroupState.STATE_SKIPPED) { - return false; - } - - GroupState foregroundGroup = getForegroundGroupState(groupState.mGroup.getName()); - if (groupState.mGroup.isBackgroundGroup() - && (foregroundGroup != null && shouldShowRequestForGroupState(foregroundGroup))) { - // If an app requests both foreground and background permissions of the same group, - // we only show one request - return false; - } - - return true; - } - - private boolean showNextPermissionGroupGrantRequest() { - int numGroupStates = mRequestGrantPermissionGroups.size(); - int numGrantRequests = 0; - for (int i = 0; i < numGroupStates; i++) { - if (shouldShowRequestForGroupState(mRequestGrantPermissionGroups.valueAt(i))) { - numGrantRequests++; - } - } - - int currentIndex = 0; - for (GroupState groupState : mRequestGrantPermissionGroups.values()) { - if (!shouldShowRequestForGroupState(groupState)) { - continue; - } - - if (groupState.mState == GroupState.STATE_UNKNOWN) { - GroupState foregroundGroupState; - GroupState backgroundGroupState; - if (groupState.mGroup.isBackgroundGroup()) { - backgroundGroupState = groupState; - foregroundGroupState = getForegroundGroupState(groupState.mGroup.getName()); - } else { - foregroundGroupState = groupState; - backgroundGroupState = getBackgroundGroupState(groupState.mGroup.getName()); - } - - CharSequence appLabel = mAppPermissions.getAppLabel(); - - // Set the new grant view - // TODO: Use a real message for the action. We need group action APIs - Resources resources; - try { - resources = getPackageManager().getResourcesForApplication( - groupState.mGroup.getIconPkg()); - } catch (NameNotFoundException e) { - // Fallback to system. - resources = Resources.getSystem(); - } - - Icon icon; - try { - icon = Icon.createWithResource(resources, groupState.mGroup.getIconResId()); - } catch (Resources.NotFoundException e) { - Log.e(LOG_TAG, "Cannot load icon for group" + groupState.mGroup.getName(), e); - icon = null; - } - - // If no background permissions are granted yet, we need to ask for background - // permissions - boolean needBackgroundPermission = false; - boolean isBackgroundPermissionUserSet = false; - if (backgroundGroupState != null) { - if (!backgroundGroupState.mGroup.areRuntimePermissionsGranted()) { - needBackgroundPermission = true; - isBackgroundPermissionUserSet = backgroundGroupState.mGroup.isUserSet(); - } - } - - // If no foreground permissions are granted yet, we need to ask for foreground - // permissions - boolean needForegroundPermission = false; - boolean isForegroundPermissionUserSet = false; - if (foregroundGroupState != null) { - if (!foregroundGroupState.mGroup.areRuntimePermissionsGranted()) { - needForegroundPermission = true; - isForegroundPermissionUserSet = foregroundGroupState.mGroup.isUserSet(); - } - } - - boolean showForegroundChooser = false; - int messageId; - int detailMessageId = 0; - if (needForegroundPermission) { - messageId = groupState.mGroup.getRequest(); - - if (needBackgroundPermission) { - showForegroundChooser = true; - } else { - if (foregroundGroupState.mGroup.hasPermissionWithBackgroundMode()) { - detailMessageId = groupState.mGroup.getRequestDetail(); - } - } - } else { - if (needBackgroundPermission) { - messageId = groupState.mGroup.getBackgroundRequest(); - detailMessageId = groupState.mGroup.getBackgroundRequestDetail(); - } else { - // Not reached as the permissions should be auto-granted - return false; - } - } - - CharSequence message = getRequestMessage(appLabel, groupState.mGroup, this, - messageId); - - Spanned detailMessage = null; - if (detailMessageId != 0) { - try { - detailMessage = Html.fromHtml( - getPackageManager().getResourcesForApplication( - groupState.mGroup.getDeclaringPackage()).getString( - detailMessageId), 0); - } catch (NameNotFoundException ignored) { - } - } - - // Set the permission message as the title so it can be announced. - setTitle(message); - - mViewHandler.updateUi(groupState.mGroup.getName(), numGrantRequests, currentIndex, - icon, message, detailMessage, showForegroundChooser, - isForegroundPermissionUserSet || isBackgroundPermissionUserSet); - - return true; - } - - if (groupState.mState != GroupState.STATE_SKIPPED) { - currentIndex++; - } - } - - return false; - } - - @Override - public void onPermissionGrantResult(String name, - @GrantPermissionsViewHandler.Result int result) { - GroupState foregroundGroupState = getForegroundGroupState(name); - GroupState backgroundGroupState = getBackgroundGroupState(name); - - switch (result) { - case GRANTED_ALWAYS : - if (foregroundGroupState != null) { - onPermissionGrantResultSingleState(foregroundGroupState, true, false); - } - if (backgroundGroupState != null) { - onPermissionGrantResultSingleState(backgroundGroupState, true, false); - } - break; - case GRANTED_FOREGROUND_ONLY : - if (foregroundGroupState != null) { - onPermissionGrantResultSingleState(foregroundGroupState, true, false); - } - if (backgroundGroupState != null) { - onPermissionGrantResultSingleState(backgroundGroupState, false, false); - } - break; - case DENIED : - if (foregroundGroupState != null) { - onPermissionGrantResultSingleState(foregroundGroupState, false, false); - } - if (backgroundGroupState != null) { - onPermissionGrantResultSingleState(backgroundGroupState, false, false); - } - break; - case DENIED_DO_NOT_ASK_AGAIN : - if (foregroundGroupState != null) { - onPermissionGrantResultSingleState(foregroundGroupState, false, true); - } - if (backgroundGroupState != null) { - onPermissionGrantResultSingleState(backgroundGroupState, false, true); - } - break; - } - - if (!showNextPermissionGroupGrantRequest()) { - setResultAndFinish(); - } - } - - /** - * Grants or revoked the affected permissions for a single {@link groupState}. - * - * @param groupState The group state with the permissions to grant/revoke - * @param granted {@code true} if the permissions should be granted, {@code false} if they - * should be revoked - * @param doNotAskAgain if the permissions should be revoked should be app be allowed to ask - * again for the same permissions? - */ - private void onPermissionGrantResultSingleState(GroupState groupState, boolean granted, - boolean doNotAskAgain) { - if (groupState != null && groupState.mGroup != null) { - if (granted) { - groupState.mGroup.grantRuntimePermissions(doNotAskAgain, - groupState.affectedPermissions); - groupState.mState = GroupState.STATE_ALLOWED; - } else { - groupState.mGroup.revokeRuntimePermissions(doNotAskAgain, - groupState.affectedPermissions); - groupState.mState = GroupState.STATE_DENIED; - - int numRequestedPermissions = mRequestedPermissions.length; - for (int i = 0; i < numRequestedPermissions; i++) { - String permission = mRequestedPermissions[i]; - - if (groupState.mGroup.hasPermission(permission)) { - EventLogger.logPermission( - MetricsProto.MetricsEvent.ACTION_PERMISSION_DENIED, permission, - mAppPermissions.getPackageInfo().packageName); - } - } - } - } - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - // We do not allow backing out. - return keyCode == KeyEvent.KEYCODE_BACK; - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - // We do not allow backing out. - return keyCode == KeyEvent.KEYCODE_BACK; - } - - @Override - public void finish() { - setResultIfNeeded(RESULT_CANCELED); - super.finish(); - } - - private PackageInfo getCallingPackageInfo() { - try { - return getPackageManager().getPackageInfo(mCallingPackage, - PackageManager.GET_PERMISSIONS); - } catch (NameNotFoundException e) { - Log.i(LOG_TAG, "No package: " + mCallingPackage, e); - return null; - } - } - - private void setResultIfNeeded(int resultCode) { - if (!mResultSet) { - mResultSet = true; - logRequestedPermissionGroups(); - Intent result = new Intent(PackageManager.ACTION_REQUEST_PERMISSIONS); - result.putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES, mRequestedPermissions); - - PackageManager pm = getPackageManager(); - int numRequestedPermissions = mRequestedPermissions.length; - int[] grantResults = new int[numRequestedPermissions]; - for (int i = 0; i < numRequestedPermissions; i++) { - grantResults[i] = pm.checkPermission(mRequestedPermissions[i], mCallingPackage); - } - - result.putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_RESULTS, grantResults); - setResult(resultCode, result); - } - } - - private void setResultAndFinish() { - setResultIfNeeded(RESULT_OK); - finish(); - } - - private void logRequestedPermissionGroups() { - if (mRequestGrantPermissionGroups.isEmpty()) { - return; - } - - final int groupCount = mRequestGrantPermissionGroups.size(); - List<AppPermissionGroup> groups = new ArrayList<>(groupCount); - for (GroupState groupState : mRequestGrantPermissionGroups.values()) { - groups.add(groupState.mGroup); - } - - SafetyNetLogger.logPermissionsRequested(mAppPermissions.getPackageInfo(), groups); - } - - /** - * Get the actually requested permissions when a permission is requested. - * - * <p>>In some cases requesting to grant a single permission requires the system to grant - * additional permissions. E.g. before N-MR1 a single permission of a group caused the whole - * group to be granted. Another case are permissions that are split into two. For apps that - * target an SDK before the split, this method automatically adds the split off permission. - * - * @param permission The requested permission - * - * @return The actually requested permissions - */ - private ArrayList<String> computeAffectedPermissions(String permission) { - int requestingAppTargetSDK = - mAppPermissions.getPackageInfo().applicationInfo.targetSdkVersion; - - // If a permission is split, all permissions the original permission is split into are - // affected - ArrayList<String> splitPerms = new ArrayList<>(); - splitPerms.add(permission); - for (PackageParser.SplitPermissionInfo splitPerm : PackageParser.SPLIT_PERMISSIONS) { - if (requestingAppTargetSDK < splitPerm.targetSdk - && permission.equals(splitPerm.rootPerm)) { - Collections.addAll(splitPerms, splitPerm.newPerms); - } - } - - // For <= N_MR1 apps all permissions of the groups of the requested permissions are affected - if (requestingAppTargetSDK <= Build.VERSION_CODES.N_MR1) { - ArrayList<String> extendedPermissions = new ArrayList<>(); - - int numSplitPerms = splitPerms.size(); - for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) { - AppPermissionGroup group = mAppPermissions.getGroupForPermission( - splitPerms.get(splitPermNum)); - - if (group == null) { - continue; - } - - ArrayList<Permission> permissionsInGroup = group.getPermissions(); - int numPermissionsInGroup = permissionsInGroup.size(); - for (int permNum = 0; permNum < numPermissionsInGroup; permNum++) { - extendedPermissions.add(permissionsInGroup.get(permNum).getName()); - } - } - - return extendedPermissions; - } else { - return splitPerms; - } - } - - private static final class GroupState { - static final int STATE_UNKNOWN = 0; - static final int STATE_ALLOWED = 1; - static final int STATE_DENIED = 2; - static final int STATE_SKIPPED = 3; - - final AppPermissionGroup mGroup; - int mState = STATE_UNKNOWN; - - /** Permissions of this group that need to be granted, null == no permissions of group */ - String[] affectedPermissions; - - GroupState(AppPermissionGroup group) { - mGroup = group; - } - } - - private class PermissionChangeListener implements PackageManager.OnPermissionsChangedListener { - final int mCallingPackageUid; - - PermissionChangeListener() throws NameNotFoundException { - mCallingPackageUid = getPackageManager().getPackageUid(mCallingPackage, 0); - } - - @Override - public void onPermissionsChanged(int uid) { - if (uid == mCallingPackageUid) { - updateIfPermissionsWereGranted(); - } - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/GrantPermissionsViewHandler.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/GrantPermissionsViewHandler.java deleted file mode 100644 index 3f637f0f2334ec81bc04c5738ac493c0c3e3a293..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/GrantPermissionsViewHandler.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui; - -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.graphics.drawable.Icon; -import android.os.Bundle; -import android.view.View; -import android.view.WindowManager; - -import androidx.annotation.IntDef; - -import java.lang.annotation.Retention; - -/** - * Class for managing the presentation and user interaction of the "grant - * permissions" user interface. - */ -public interface GrantPermissionsViewHandler { - @Retention(SOURCE) - @IntDef({GRANTED_ALWAYS, GRANTED_FOREGROUND_ONLY, DENIED, DENIED_DO_NOT_ASK_AGAIN}) - @interface Result {} - int GRANTED_ALWAYS = 0; - int GRANTED_FOREGROUND_ONLY = 1; - int DENIED = 2; - int DENIED_DO_NOT_ASK_AGAIN = 3; - - /** - * Listener interface for getting notified when the user responds to a - * permissions grant request. - */ - interface ResultListener { - void onPermissionGrantResult(String groupName, @Result int result); - } - - /** - * Creates and returns the view hierarchy that is managed by this view - * handler. This must be called before {@link #updateUi}. - */ - View createView(); - - /** - * Updates the layout attributes of the current window. This is an optional - * operation; implementations only need to do work in this method if they - * need to alter the default styles provided by the activity's theme. - */ - void updateWindowAttributes(WindowManager.LayoutParams outLayoutParams); - - /** - * Updates the view hierarchy to reflect the specified state. - * <p> - * Note that this must be called at least once before showing the UI to - * the user to properly initialize the UI. - * - * @param groupName the name of the permission group - * @param groupCount the total number of groups that are being requested - * @param groupIndex the index of the current group being requested - * @param icon the icon representation of the current group - * @param message the message to display the user - * @param detailMessage another message to display to the user. This clarifies "message" in more - * detail - * @param showForegroundChooser whether to show the "only in foreground / always" option - * @param showDoNotAsk whether to show the "do not ask again" option - */ - void updateUi(String groupName, int groupCount, int groupIndex, Icon icon, - CharSequence message, CharSequence detailMessage, boolean showForegroundChooser, - boolean showDoNotAsk); - - /** - * Sets the result listener that will be notified when the user responds - * to a permissions grant request. - */ - GrantPermissionsViewHandler setResultListener(ResultListener listener); - - /** - * Called by {@link GrantPermissionsActivity} to save the state of this - * view handler to the specified bundle. - */ - void saveInstanceState(Bundle outState); - - /** - * Called by {@link GrantPermissionsActivity} to load the state of this - * view handler from the specified bundle. - */ - void loadInstanceState(Bundle savedInstanceState); - - /** - * Gives a chance for handling the back key. - */ - void onBackPressed(); -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java deleted file mode 100644 index f2251c1f3e7f0248aa7ac57d96a38d8f56755b0f..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java +++ /dev/null @@ -1,216 +0,0 @@ -package com.android.packageinstaller.permission.ui; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.res.TypedArray; -import android.graphics.PixelFormat; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.Icon; -import android.os.Bundle; -import android.text.SpannableStringBuilder; -import android.text.Spanned; -import android.text.TextUtils; -import android.text.style.TextAppearanceSpan; -import android.util.Log; -import android.view.View; -import android.view.WindowManager; -import android.widget.Space; - -import androidx.wear.ble.view.AcceptDenyDialog; -import androidx.wear.ble.view.WearableDialogHelper; - -import com.android.packageinstaller.R; - -/** - * Watch-specific view handler for the grant permissions activity. - */ -final class GrantPermissionsWatchViewHandler implements GrantPermissionsViewHandler, - DialogInterface.OnClickListener { - private static final String TAG = "GrantPermsWatchViewH"; - - private static final String WATCH_HANDLER_BUNDLE = "watch_handler_bundle"; - private static final String DIALOG_BUNDLE = "dialog_bundle"; - private static final String GROUP_NAME = "group_name"; - private static final String SHOW_DO_NOT_ASK = "show_do_not_ask"; - private static final String ICON = "icon"; - private static final String MESSAGE = "message"; - private static final String CURRENT_PAGE_TEXT = "current_page_text"; - - private final Context mContext; - - private ResultListener mResultListener; - - private Dialog mDialog; - - private String mGroupName; - private boolean mShowDoNotAsk; - - private CharSequence mMessage; - private String mCurrentPageText; - private Icon mIcon; - - GrantPermissionsWatchViewHandler(Context context) { - mContext = context; - } - - @Override - public GrantPermissionsWatchViewHandler setResultListener(ResultListener listener) { - mResultListener = listener; - return this; - } - - @Override - public View createView() { - return new Space(mContext); - } - - @Override - public void updateWindowAttributes(WindowManager.LayoutParams outLayoutParams) { - outLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; - outLayoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; - outLayoutParams.format = PixelFormat.OPAQUE; - outLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; - outLayoutParams.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; - } - - @Override - public void updateUi(String groupName, int groupCount, int groupIndex, Icon icon, - CharSequence message, CharSequence detailMessage, boolean showForegroundChooser, - boolean showDoNotAsk) { - // TODO: Handle detailMessage - // TODO: Handle showForegroundChooser - - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "updateUi() - groupName: " + groupName - + ", groupCount: " + groupCount - + ", groupIndex: " + groupIndex - + ", icon: " + icon - + ", message: " + message - + ", showDoNotAsk: " + showDoNotAsk); - } - - mGroupName = groupName; - mShowDoNotAsk = showDoNotAsk; - mMessage = message; - mIcon = icon; - mCurrentPageText = groupCount > 1 - ? mContext.getString(R.string.current_permission_template, - groupIndex + 1, groupCount) - : null; - showDialog(null); - } - - private void showDialog(Bundle savedInstanceState) { - TypedArray a = mContext.obtainStyledAttributes( - new int[] { android.R.attr.textColorPrimary }); - int color = a.getColor(0, mContext.getColor(android.R.color.white)); - a.recycle(); - Drawable drawable = mIcon == null ? null : mIcon.setTint(color).loadDrawable(mContext); - - SpannableStringBuilder ssb = new SpannableStringBuilder(); - if (!TextUtils.isEmpty(mCurrentPageText)) { - ssb.append(mCurrentPageText, new TextAppearanceSpan(mContext, R.style.BreadcrumbText), - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - ssb.append('\n'); - } - if (!TextUtils.isEmpty(mMessage)) { - ssb.append(mMessage, new TextAppearanceSpan(mContext, R.style.TitleText), - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } - - if (mDialog != null) { - mDialog.dismiss(); - mDialog = null; - } - - if (mShowDoNotAsk) { - AlertDialog alertDialog = new WearableDialogHelper.DialogBuilder(mContext) - .setPositiveIcon(R.drawable.confirm_button) - .setNeutralIcon(R.drawable.cancel_button) - .setNegativeIcon(R.drawable.deny_button) - .setTitle(ssb) - .setIcon(drawable) - .setPositiveButton(R.string.grant_dialog_button_allow, this) - .setNeutralButton(R.string.grant_dialog_button_deny, this) - .setNegativeButton(R.string.grant_dialog_button_deny_dont_ask_again, this) - .show(); - alertDialog.getButton(DialogInterface.BUTTON_POSITIVE) - .setId(R.id.permission_allow_button); - alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL) - .setId(R.id.permission_deny_button); - alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE) - .setId(R.id.permission_deny_dont_ask_again_button); - - mDialog = alertDialog; - } else { - AcceptDenyDialog acceptDenyDialog = new AcceptDenyDialog(mContext); - acceptDenyDialog.setTitle(ssb); - acceptDenyDialog.setIcon(drawable); - acceptDenyDialog.setPositiveButton(this); - acceptDenyDialog.setNegativeButton(this); - acceptDenyDialog.show(); - acceptDenyDialog.getButton(DialogInterface.BUTTON_POSITIVE) - .setId(R.id.permission_allow_button); - acceptDenyDialog.getButton(DialogInterface.BUTTON_NEGATIVE) - .setId(R.id.permission_deny_button); - - mDialog = acceptDenyDialog; - } - mDialog.setCancelable(false); - - if (savedInstanceState != null) { - mDialog.onRestoreInstanceState(savedInstanceState); - } - } - - @Override - public void saveInstanceState(Bundle outState) { - Bundle b = new Bundle(); - b.putByte(SHOW_DO_NOT_ASK, (byte) (mShowDoNotAsk ? 1 : 0)); - b.putString(GROUP_NAME, mGroupName); - b.putBundle(DIALOG_BUNDLE, mDialog.onSaveInstanceState()); - - outState.putBundle(WATCH_HANDLER_BUNDLE, b); - } - - @Override - public void loadInstanceState(Bundle savedInstanceState) { - Bundle b = savedInstanceState.getBundle(WATCH_HANDLER_BUNDLE); - mShowDoNotAsk = b.getByte(SHOW_DO_NOT_ASK) == 1; - mGroupName = b.getString(GROUP_NAME); - showDialog(b.getBundle(DIALOG_BUNDLE)); - } - - @Override - public void onBackPressed() { - notifyListener(DENIED); - } - - @Override - public void onClick(DialogInterface dialog, int which) { - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - notifyListener(GRANTED_ALWAYS); - break; - case DialogInterface.BUTTON_NEUTRAL: - notifyListener(DENIED); - break; - case DialogInterface.BUTTON_NEGATIVE: - /* In AlertDialog, the negative button is also a don't ask again button. */ - if (dialog instanceof AlertDialog) { - notifyListener(DENIED_DO_NOT_ASK_AGAIN); - } else { - notifyListener(DENIED); - } - break; - } - } - - private void notifyListener(@Result int result) { - if (mResultListener != null) { - mResultListener.onPermissionGrantResult(mGroupName, result); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java deleted file mode 100644 index 712b860c504715bc762628f844616d7a66109144..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java +++ /dev/null @@ -1,128 +0,0 @@ -/* -* Copyright (C) 2015 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package com.android.packageinstaller.permission.ui; - -import android.app.Fragment; -import android.content.Intent; -import android.os.Bundle; -import android.util.Log; -import android.view.MenuItem; - -import com.android.packageinstaller.DeviceUtils; -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.ui.handheld.ManageStandardPermissionsFragment; -import com.android.packageinstaller.permission.ui.wear.AppPermissionsFragmentWear; - -public final class ManagePermissionsActivity extends OverlayTouchActivity { - private static final String LOG_TAG = "ManagePermissionsActivity"; - - public static final String EXTRA_ALL_PERMISSIONS = - "com.android.packageinstaller.extra.ALL_PERMISSIONS"; - - @Override - public void onCreate(Bundle savedInstanceState) { - if (DeviceUtils.isAuto(this)) { - setTheme(R.style.CarSettingTheme); - } - super.onCreate(savedInstanceState); - - if (savedInstanceState != null) { - return; - } - - Fragment fragment; - String action = getIntent().getAction(); - - switch (action) { - case Intent.ACTION_MANAGE_PERMISSIONS: { - if (DeviceUtils.isTelevision(this)) { - fragment = com.android.packageinstaller.permission.ui.television - .ManagePermissionsFragment.newInstance(); - } else { - fragment = ManageStandardPermissionsFragment.newInstance(); - } - } break; - - case Intent.ACTION_MANAGE_APP_PERMISSIONS: { - String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME); - if (packageName == null) { - Log.i(LOG_TAG, "Missing mandatory argument EXTRA_PACKAGE_NAME"); - finish(); - return; - } - if (DeviceUtils.isAuto(this)) { - fragment = com.android.packageinstaller.permission.ui.auto - .AppPermissionsFragment.newInstance(packageName); - } else if (DeviceUtils.isWear(this)) { - fragment = AppPermissionsFragmentWear.newInstance(packageName); - } else if (DeviceUtils.isTelevision(this)) { - fragment = com.android.packageinstaller.permission.ui.television - .AppPermissionsFragment.newInstance(packageName); - } else { - final boolean allPermissions = getIntent().getBooleanExtra( - EXTRA_ALL_PERMISSIONS, false); - if (allPermissions) { - fragment = com.android.packageinstaller.permission.ui.handheld - .AllAppPermissionsFragment.newInstance(packageName); - } else { - fragment = com.android.packageinstaller.permission.ui.handheld - .AppPermissionsFragment.newInstance(packageName); - } - } - } break; - - case Intent.ACTION_MANAGE_PERMISSION_APPS: { - String permissionName = getIntent().getStringExtra(Intent.EXTRA_PERMISSION_NAME); - if (permissionName == null) { - Log.i(LOG_TAG, "Missing mandatory argument EXTRA_PERMISSION_NAME"); - finish(); - return; - } - if (DeviceUtils.isTelevision(this)) { - fragment = com.android.packageinstaller.permission.ui.television - .PermissionAppsFragment.newInstance(permissionName); - } else { - fragment = com.android.packageinstaller.permission.ui.handheld - .PermissionAppsFragment.newInstance(permissionName); - } - } break; - - default: { - Log.w(LOG_TAG, "Unrecognized action " + action); - finish(); - return; - } - } - - getFragmentManager().beginTransaction().replace(android.R.id.content, fragment).commit(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // in automotive mode, there's no system wide back button, so need to add that - if (DeviceUtils.isAuto(this)) { - switch (item.getItemId()) { - case android.R.id.home: - onBackPressed(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - return super.onOptionsItemSelected(item); - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ManualLayoutFrame.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ManualLayoutFrame.java deleted file mode 100644 index 0b07c806e5e6184271ec87629c2042c22859d5ec..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ManualLayoutFrame.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.packageinstaller.permission.ui; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.view.ViewGroup; - -public class ManualLayoutFrame extends ViewGroup { - private int mContentBottom; - private int mWidth; - - public ManualLayoutFrame(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public void onConfigurationChanged() { - mContentBottom = 0; - mWidth = 0; - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (mWidth != 0) { - int newWidth = mWidth; - final int widthMode = MeasureSpec.getMode(widthMeasureSpec); - switch (widthMode) { - case MeasureSpec.AT_MOST: { - newWidth = Math.min(mWidth, MeasureSpec.getSize(widthMeasureSpec)); - } break; - case MeasureSpec.EXACTLY: { - newWidth = MeasureSpec.getSize(widthMeasureSpec); - } break; - } - if (newWidth != mWidth) { - mWidth = newWidth; - } - widthMeasureSpec = MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY); - } - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - if (mWidth == 0) { - mWidth = getMeasuredWidth(); - } - - measureChild(getChildAt(0), widthMeasureSpec, heightMeasureSpec); - } - - @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 || content.getMeasuredHeight() > mContentBottom) { - mContentBottom = (getMeasuredHeight() + content.getMeasuredHeight()) / 2; - } - final int contentLeft = (getMeasuredWidth() - content.getMeasuredWidth()) / 2; - final int contentTop = mContentBottom - content.getMeasuredHeight(); - final int contentRight = contentLeft + content.getMeasuredWidth(); - content.layout(contentLeft, contentTop, contentRight, mContentBottom); - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/OverlayWarningDialog.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/OverlayWarningDialog.java deleted file mode 100644 index 61734b470c785b35e0dc71a019454994e2ef857b..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/OverlayWarningDialog.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.ActivityNotFoundException; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.DialogInterface.OnDismissListener; -import android.content.Intent; -import android.os.Bundle; -import android.provider.Settings; -import android.util.Log; - -import com.android.packageinstaller.R; - -public class OverlayWarningDialog extends Activity implements OnClickListener, OnDismissListener { - - private static final String TAG = "OverlayWarningDialog"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - new AlertDialog.Builder(this) - .setTitle(R.string.screen_overlay_title) - .setMessage(R.string.screen_overlay_message) - .setPositiveButton(R.string.screen_overlay_button, this) - .setOnDismissListener(this) - .show(); - } - - @Override - public void onDismiss(DialogInterface dialog) { - finish(); - } - - @Override - public void onClick(DialogInterface dialog, int which) { - finish(); - try { - startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)); - } catch (ActivityNotFoundException e) { - Log.w(TAG, "No manage overlay settings", e); - } - } - -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/PreferenceImageView.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/PreferenceImageView.java deleted file mode 100644 index c3f516744ce282015ba6269e026a0f7c20426614..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/PreferenceImageView.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.ImageView; - -/** - * Extension of ImageView that correctly applies maxWidth and maxHeight. - */ -public class PreferenceImageView extends ImageView { - - public PreferenceImageView(Context context) { - this(context, null); - } - - public PreferenceImageView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public PreferenceImageView(Context context, AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); - } - - public PreferenceImageView(Context context, AttributeSet attrs, int defStyleAttr, - int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - final int widthMode = MeasureSpec.getMode(widthMeasureSpec); - if (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED) { - final int widthSize = MeasureSpec.getSize(widthMeasureSpec); - final int maxWidth = getMaxWidth(); - if (maxWidth != Integer.MAX_VALUE - && (maxWidth < widthSize || widthMode == MeasureSpec.UNSPECIFIED)) { - widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST); - } - } - - final int heightMode = MeasureSpec.getMode(heightMeasureSpec); - if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) { - final int heightSize = MeasureSpec.getSize(heightMeasureSpec); - final int maxHeight = getMaxHeight(); - if (maxHeight != Integer.MAX_VALUE - && (maxHeight < heightSize || heightMode == MeasureSpec.UNSPECIFIED)) { - heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST); - } - } - - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ReviewPermissionsActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ReviewPermissionsActivity.java deleted file mode 100644 index e4929c7e947e666b41c41ca39cf2f4be36878265..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/ReviewPermissionsActivity.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui; - -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.text.TextUtils; - -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; - -import com.android.packageinstaller.DeviceUtils; -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.ui.ConfirmActionDialogFragment - .OnActionConfirmedListener; -import com.android.packageinstaller.permission.ui.handheld.ReviewPermissionsFragment; -import com.android.packageinstaller.permission.ui.wear.ReviewPermissionsWearFragment; - -public final class ReviewPermissionsActivity extends FragmentActivity - implements OnActionConfirmedListener { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - PackageInfo packageInfo = getTargetPackageInfo(); - if (packageInfo == null) { - finish(); - return; - } - - if (DeviceUtils.isWear(this)) { - Fragment fragment = ReviewPermissionsWearFragment.newInstance(packageInfo); - getSupportFragmentManager().beginTransaction() - .replace(android.R.id.content, fragment).commit(); - } else { - setContentView(R.layout.review_permissions); - if (getSupportFragmentManager().findFragmentById(R.id.preferences_frame) == null) { - getSupportFragmentManager().beginTransaction().add(R.id.preferences_frame, - ReviewPermissionsFragment.newInstance(packageInfo)).commit(); - } - } - } - - @Override - public void onActionConfirmed(String action) { - Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.preferences_frame); - if (fragment instanceof OnActionConfirmedListener) { - ((OnActionConfirmedListener) fragment).onActionConfirmed(action); - } - } - - private PackageInfo getTargetPackageInfo() { - String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME); - if (TextUtils.isEmpty(packageName)) { - return null; - } - try { - return getPackageManager().getPackageInfo(packageName, - PackageManager.GET_PERMISSIONS); - } catch (PackageManager.NameNotFoundException e) { - return null; - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/auto/AppPermissionsFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/auto/AppPermissionsFragment.java deleted file mode 100644 index 9bc75fc4ea7f795c73009a6b55b1921d14c598c9..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/auto/AppPermissionsFragment.java +++ /dev/null @@ -1,204 +0,0 @@ -/** - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.auto; - - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Fragment; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Toast; - -import androidx.car.widget.ListItem; -import androidx.car.widget.ListItemAdapter; -import androidx.car.widget.ListItemProvider; -import androidx.car.widget.PagedListView; -import androidx.car.widget.TextListItem; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.AppPermissions; -import com.android.packageinstaller.permission.utils.Utils; - -import java.util.ArrayList; - -/** - * Contains all permissions in a list for a given application. - */ -public final class AppPermissionsFragment extends Fragment{ - - private static final String LOG_TAG = "ManagePermsFragment"; - public static final String EXTRA_LAYOUT = "extra_layout"; - - private AppPermissions mAppPermissions; - - private String mPackageName; - - protected PagedListView mListView; - protected ListItemAdapter mPagedListAdapter; - - - /** - * Creates a new instance. - * @param packageName the packageName of the application that we are listing the - * permissions here. - */ - public static AppPermissionsFragment newInstance(String packageName) { - AppPermissionsFragment fragment = new AppPermissionsFragment(); - Bundle arguments = new Bundle(); - arguments.putInt(EXTRA_LAYOUT, R.layout.car_app_permissions); - arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName); - fragment.setArguments(arguments); - return fragment; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - getView().findViewById(R.id.action_bar_icon_container).setOnClickListener( - v -> getActivity().onBackPressed()); - - mListView = (PagedListView) getView().findViewById(R.id.list); - mPagedListAdapter = new ListItemAdapter(getContext(), getItemProvider()); - mListView.setAdapter(mPagedListAdapter); - } - - protected void notifyDataSetChanged() { - mPagedListAdapter.notifyDataSetChanged(); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (savedInstanceState != null - && savedInstanceState.containsKey(Intent.EXTRA_PACKAGE_NAME)) { - mPackageName = savedInstanceState.getString(Intent.EXTRA_PACKAGE_NAME); - } else if (getArguments() != null - && getArguments().containsKey(Intent.EXTRA_PACKAGE_NAME)) { - mPackageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME); - } - - if (mPackageName == null) { - Log.e(LOG_TAG, "package name is missing"); - return; - } - Activity activity = getActivity(); - PackageInfo packageInfo = getPackageInfo(activity, mPackageName); - if (packageInfo == null) { - Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show(); - activity.finish(); - return; - } - - mAppPermissions = new AppPermissions(activity, packageInfo, true, new Runnable() { - @Override - public void run() { - activity.finish(); - } - }); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString(Intent.EXTRA_PACKAGE_NAME, mPackageName); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - return inflater.inflate(getArguments().getInt(EXTRA_LAYOUT), container, false); - } - - @Override - public void onResume() { - super.onResume(); - mAppPermissions.refresh(); - } - - /** - * Gets the list of the LineItems to show up in the list - */ - public ListItemProvider getItemProvider() { - ArrayList<ListItem> items = new ArrayList<>(); - Context context = getContext(); - if (context == null) { - return new ListItemProvider.ListProvider(items); - } - - for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { - if (!Utils.shouldShowPermission(group)) { - continue; - } - items.add(new PermissionLineItem(group, context)); - } - return new ListItemProvider.ListProvider(items); - } - - private static PackageInfo getPackageInfo(Activity activity, String packageName) { - try { - return activity.getPackageManager().getPackageInfo( - packageName, PackageManager.GET_PERMISSIONS); - } catch (PackageManager.NameNotFoundException e) { - if (Log.isLoggable(LOG_TAG, Log.INFO)) { - Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e); - } - return null; - } - } - - private class PermissionLineItem extends TextListItem { - - PermissionLineItem(AppPermissionGroup permissionGroup, Context context) { - super(context); - setTitle(permissionGroup.getLabel().toString()); - setPrimaryActionIcon(permissionGroup.getIconResId(), /* useLargeIcon= */ false); - setSwitch( - permissionGroup.areRuntimePermissionsGranted(), - /* showDivider= */ false, - (button, isChecked) -> { - if (isChecked) { - permissionGroup.grantRuntimePermissions(/* fixedByTheUser= */ false); - return; - } - boolean grantedByDefault = permissionGroup.hasGrantedByDefaultPermission(); - if (!grantedByDefault && permissionGroup.doesSupportRuntimePermissions()) { - permissionGroup.revokeRuntimePermissions(/* fixedByTheUser= */ false); - return; - } - new AlertDialog.Builder(context) - .setMessage(grantedByDefault - ? R.string.system_warning - : R.string.old_sdk_deny_warning) - .setNegativeButton(R.string.cancel, /* listener= */ null) - .setPositiveButton(R.string.grant_dialog_button_deny_anyway, - (dialog, which) -> - permissionGroup.revokeRuntimePermissions( - /* fixedByTheUser= */ false)) - .show(); - }); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/auto/GrantPermissionsAutoViewHandler.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/auto/GrantPermissionsAutoViewHandler.java deleted file mode 100644 index 9e40d6643970f54343dfa009da1e68bda9b13f61..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/auto/GrantPermissionsAutoViewHandler.java +++ /dev/null @@ -1,46 +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.auto; - -import android.app.Activity; -import android.view.WindowManager; - -import com.android.packageinstaller.permission.ui.handheld.GrantPermissionsViewHandlerImpl; - -/** - * A {@link com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler} that is - * specific for the auto use-case. In this case, the permissions dialog needs to be larger to make - * clicking and reading safer in the car. Otherwise, the UI remains the same. - * - * <p>The reason this class extends {@link GrantPermissionsViewHandlerImpl} is so that it can - * change the window params to allow the dialog's width to be larger. - */ -public class GrantPermissionsAutoViewHandler extends GrantPermissionsViewHandlerImpl { - public GrantPermissionsAutoViewHandler(Activity activity, String appPackageName) { - super(activity, appPackageName); - } - - /** - * Update the given {@link android.view.WindowManager.LayoutParams} to allow the dialog to take - * up the entirety of the width. - */ - @Override - public void updateWindowAttributes(WindowManager.LayoutParams outLayoutParams) { - outLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; - outLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/AllAppPermissionsFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/AllAppPermissionsFragment.java deleted file mode 100644 index 1d8e5adfcaf0fd752bf6f97d2659083b08d7575e..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/AllAppPermissionsFragment.java +++ /dev/null @@ -1,378 +0,0 @@ -/* -* Copyright (C) 2015 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package com.android.packageinstaller.permission.ui.handheld; - -import android.app.ActionBar; -import android.app.AlertDialog; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageItemInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.PermissionGroupInfo; -import android.content.pm.PermissionInfo; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.preference.Preference; -import android.preference.PreferenceCategory; -import android.preference.PreferenceGroup; -import android.provider.Settings; -import android.util.IconDrawableFactory; -import android.util.Log; -import android.view.MenuItem; -import android.widget.Switch; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.Permission; -import com.android.packageinstaller.permission.utils.ArrayUtils; -import com.android.packageinstaller.permission.utils.Utils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -/** - * Show and manage individual permissions for an app. - * - * <p>Shows the list of individual runtime and non-runtime permissions the app has requested. - */ -public final class AllAppPermissionsFragment extends SettingsWithHeader { - - private static final String LOG_TAG = "AllAppPermissionsFragment"; - - private static final String KEY_OTHER = "other_perms"; - - private static final String EXTRA_FILTER_GROUP = - "com.android.packageinstaller.extra.FILTER_GROUP"; - - private List<AppPermissionGroup> mGroups; - - public static AllAppPermissionsFragment newInstance(String packageName) { - return newInstance(packageName, null); - } - - public static AllAppPermissionsFragment newInstance(String packageName, String filterGroup) { - AllAppPermissionsFragment instance = new AllAppPermissionsFragment(); - Bundle arguments = new Bundle(); - arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName); - arguments.putString(EXTRA_FILTER_GROUP, filterGroup); - instance.setArguments(arguments); - return instance; - } - - @Override - public void onStart() { - super.onStart(); - - final ActionBar ab = getActivity().getActionBar(); - if (ab != null) { - // If we target a group make this look like app permissions. - if (getArguments().getString(EXTRA_FILTER_GROUP) == null) { - ab.setTitle(R.string.all_permissions); - } else { - ab.setTitle(R.string.app_permissions); - } - ab.setDisplayHomeAsUpEnabled(true); - } - - setHasOptionsMenu(true); - - updateUi(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: { - getFragmentManager().popBackStack(); - return true; - } - } - return super.onOptionsItemSelected(item); - } - - private void updateUi() { - if (getPreferenceScreen() != null) { - getPreferenceScreen().removeAll(); - } - addPreferencesFromResource(R.xml.all_permissions); - PreferenceGroup otherGroup = (PreferenceGroup) findPreference(KEY_OTHER); - ArrayList<Preference> prefs = new ArrayList<>(); // Used for sorting. - prefs.add(otherGroup); - String pkg = getArguments().getString(Intent.EXTRA_PACKAGE_NAME); - String filterGroup = getArguments().getString(EXTRA_FILTER_GROUP); - otherGroup.removeAll(); - PackageManager pm = getContext().getPackageManager(); - - try { - PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_PERMISSIONS); - - ApplicationInfo appInfo = info.applicationInfo; - final Drawable icon = - IconDrawableFactory.newInstance(getContext()).getBadgedIcon(appInfo); - final CharSequence label = appInfo.loadLabel(pm); - Intent infoIntent = null; - if (!getActivity().getIntent().getBooleanExtra( - AppPermissionsFragment.EXTRA_HIDE_INFO_BUTTON, false)) { - infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) - .setData(Uri.fromParts("package", pkg, null)); - } - setHeader(icon, label, infoIntent); - - if (info.requestedPermissions != null) { - for (int i = 0; i < info.requestedPermissions.length; i++) { - PermissionInfo perm; - try { - perm = pm.getPermissionInfo(info.requestedPermissions[i], 0); - } catch (NameNotFoundException e) { - Log.e(LOG_TAG, - "Can't get permission info for " + info.requestedPermissions[i], e); - continue; - } - - if ((perm.flags & PermissionInfo.FLAG_INSTALLED) == 0 - || (perm.flags & PermissionInfo.FLAG_REMOVED) != 0) { - continue; - } - - if (appInfo.isInstantApp() - && (perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) - == 0) { - continue; - } - if (appInfo.targetSdkVersion < Build.VERSION_CODES.M - && (perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) - != 0) { - continue; - } - - if ((perm.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) - == PermissionInfo.PROTECTION_DANGEROUS) { - PackageItemInfo group = getGroup(perm.group, pm); - if (group == null) { - group = perm; - } - // If we show a targeted group, then ignore everything else. - if (filterGroup != null && !group.name.equals(filterGroup)) { - continue; - } - PreferenceGroup pref = findOrCreate(group, pm, prefs); - pref.addPreference(getPreference(info, perm, group, pm)); - } else if (filterGroup == null) { - if ((perm.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) - == PermissionInfo.PROTECTION_NORMAL) { - PermissionGroupInfo group = getGroup(perm.group, pm); - otherGroup.addPreference(getPreference(info, - perm, group, pm)); - } - } - - // If we show a targeted group, then don't show 'other' permissions. - if (filterGroup != null) { - getPreferenceScreen().removePreference(otherGroup); - } - } - } - } catch (NameNotFoundException e) { - Log.e(LOG_TAG, "Problem getting package info for " + pkg, e); - } - // Sort an ArrayList of the groups and then set the order from the sorting. - Collections.sort(prefs, new Comparator<Preference>() { - @Override - public int compare(Preference lhs, Preference rhs) { - String lKey = lhs.getKey(); - String rKey = rhs.getKey(); - if (lKey.equals(KEY_OTHER)) { - return 1; - } else if (rKey.equals(KEY_OTHER)) { - return -1; - } else if (Utils.isModernPermissionGroup(lKey) - != Utils.isModernPermissionGroup(rKey)) { - return Utils.isModernPermissionGroup(lKey) ? -1 : 1; - } - return lhs.getTitle().toString().compareTo(rhs.getTitle().toString()); - } - }); - for (int i = 0; i < prefs.size(); i++) { - prefs.get(i).setOrder(i); - } - } - - private PermissionGroupInfo getGroup(String group, PackageManager pm) { - try { - return pm.getPermissionGroupInfo(group, 0); - } catch (NameNotFoundException e) { - return null; - } - } - - private PreferenceGroup findOrCreate(PackageItemInfo group, PackageManager pm, - ArrayList<Preference> prefs) { - PreferenceGroup pref = (PreferenceGroup) findPreference(group.name); - if (pref == null) { - pref = new PreferenceCategory(getContext()); - pref.setKey(group.name); - pref.setTitle(group.loadLabel(pm)); - prefs.add(pref); - getPreferenceScreen().addPreference(pref); - } - return pref; - } - - private Preference getPreference(PackageInfo packageInfo, PermissionInfo perm, - PackageItemInfo group, PackageManager pm) { - final Preference pref; - - // We allow individual permission control for some permissions if review enabled - final boolean mutable = Utils.isPermissionIndividuallyControlled(getContext(), perm.name); - if (mutable) { - pref = new MyMultiTargetSwitchPreference(getContext(), perm.name, - getPermissionForegroundGroup(packageInfo, perm.name)); - } else { - pref = new Preference(getContext()); - } - - Drawable icon = null; - if (perm.icon != 0) { - icon = perm.loadIcon(pm); - } else if (group != null && group.icon != 0) { - icon = group.loadIcon(pm); - } else { - icon = getContext().getDrawable(R.drawable.ic_perm_device_info); - } - pref.setIcon(Utils.applyTint(getContext(), icon, android.R.attr.colorControlNormal)); - pref.setTitle(perm.loadSafeLabel(pm, 20000, PackageItemInfo.SAFE_LABEL_FLAG_TRIM)); - pref.setSingleLineTitle(false); - final CharSequence desc = perm.loadDescription(pm); - - pref.setOnPreferenceClickListener((Preference preference) -> { - new AlertDialog.Builder(getContext()) - .setMessage(desc) - .setPositiveButton(android.R.string.ok, null) - .show(); - return mutable; - }); - - return pref; - } - - /** - * Return the (foreground-) {@link AppPermissionGroup group} a permission belongs to. - * - * <p>For foreground or non background-foreground permissions this returns the group - * {@link AppPermissionGroup} the permission is in. For background permisisons this returns - * the group the matching foreground - * - * @param packageInfo Package information about the app - * @param permission The permission that belongs to a group - * - * @return the group the permissions belongs to - */ - private AppPermissionGroup getPermissionForegroundGroup(PackageInfo packageInfo, - String permission) { - AppPermissionGroup appPermissionGroup = null; - if (mGroups != null) { - final int groupCount = mGroups.size(); - for (int i = 0; i < groupCount; i++) { - AppPermissionGroup currentPermissionGroup = mGroups.get(i); - if (currentPermissionGroup.hasPermission(permission)) { - appPermissionGroup = currentPermissionGroup; - break; - } - if (currentPermissionGroup.getBackgroundPermissions() != null - && currentPermissionGroup.getBackgroundPermissions().hasPermission( - permission)) { - appPermissionGroup = currentPermissionGroup.getBackgroundPermissions(); - break; - } - } - } - if (appPermissionGroup == null) { - appPermissionGroup = AppPermissionGroup.create( - getContext(), packageInfo, permission); - if (mGroups == null) { - mGroups = new ArrayList<>(); - } - mGroups.add(appPermissionGroup); - } - return appPermissionGroup; - } - - private static final class MyMultiTargetSwitchPreference extends MultiTargetSwitchPreference { - MyMultiTargetSwitchPreference(Context context, String permission, - AppPermissionGroup appPermissionGroup) { - super(context); - - setChecked(appPermissionGroup.areRuntimePermissionsGranted( - new String[] {permission})); - - setSwitchOnClickListener(v -> { - Switch switchView = (Switch) v; - if (switchView.isChecked()) { - appPermissionGroup.grantRuntimePermissions(false, - new String[]{permission}); - // We are granting a permission from a group but since this is an - // individual permission control other permissions in the group may - // be revoked, hence we need to mark them user fixed to prevent the - // app from requesting a non-granted permission and it being granted - // because another permission in the group is granted. This applies - // only to apps that support runtime permissions. - if (appPermissionGroup.doesSupportRuntimePermissions()) { - int grantedCount = 0; - String[] revokedPermissionsToFix = null; - final int permissionCount = appPermissionGroup.getPermissions().size(); - for (int i = 0; i < permissionCount; i++) { - Permission current = appPermissionGroup.getPermissions().get(i); - if (!current.isGranted()) { - if (!current.isUserFixed()) { - revokedPermissionsToFix = ArrayUtils.appendString( - revokedPermissionsToFix, current.getName()); - } - } else { - grantedCount++; - } - } - if (revokedPermissionsToFix != null) { - // If some permissions were not granted then they should be fixed. - appPermissionGroup.revokeRuntimePermissions(true, - revokedPermissionsToFix); - } else if (appPermissionGroup.getPermissions().size() == grantedCount) { - // If all permissions are granted then they should not be fixed. - appPermissionGroup.grantRuntimePermissions(false); - } - } - } else { - appPermissionGroup.revokeRuntimePermissions(true, - new String[]{permission}); - // If we just revoked the last permission we need to clear - // the user fixed state as now the app should be able to - // request them at runtime if supported. - if (appPermissionGroup.doesSupportRuntimePermissions() - && !appPermissionGroup.areRuntimePermissionsGranted()) { - appPermissionGroup.revokeRuntimePermissions(false); - } - } - }); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/AppPermissionsFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/AppPermissionsFragment.java deleted file mode 100644 index 917f238b81111ee162c3150200badf85aeafe19e..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/AppPermissionsFragment.java +++ /dev/null @@ -1,331 +0,0 @@ -/* -* Copyright (C) 2015 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package com.android.packageinstaller.permission.ui.handheld; - -import android.app.ActionBar; -import android.app.Activity; -import android.app.Fragment; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Bundle; -import android.preference.Preference; -import android.preference.Preference.OnPreferenceClickListener; -import android.preference.PreferenceScreen; -import android.provider.Settings; -import android.util.ArraySet; -import android.util.IconDrawableFactory; -import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.Toast; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.AppPermissions; -import com.android.packageinstaller.permission.utils.SafetyNetLogger; -import com.android.packageinstaller.permission.utils.Utils; -import com.android.settingslib.HelpUtils; - -/** - * Show and manage permission groups for an app. - * - * <p>Shows the list of permission groups the app has requested at one permission for. - */ -public final class AppPermissionsFragment extends SettingsWithHeader - implements PermissionPreference.PermissionPreferenceChangeListener, - PermissionPreference.PermissionPreferenceOwnerFragment { - - private static final String LOG_TAG = "ManagePermsFragment"; - - static final String EXTRA_HIDE_INFO_BUTTON = "hideInfoButton"; - - private static final int MENU_ALL_PERMS = 0; - - private ArraySet<AppPermissionGroup> mToggledGroups; - private AppPermissions mAppPermissions; - private PreferenceScreen mExtraScreen; - - private boolean mHasConfirmedRevoke; - - public static AppPermissionsFragment newInstance(String packageName) { - return setPackageName(new AppPermissionsFragment(), packageName); - } - - private static <T extends Fragment> T setPackageName(T fragment, String packageName) { - Bundle arguments = new Bundle(); - arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName); - fragment.setArguments(arguments); - return fragment; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setLoading(true /* loading */, false /* animate */); - setHasOptionsMenu(true); - final ActionBar ab = getActivity().getActionBar(); - if (ab != null) { - ab.setDisplayHomeAsUpEnabled(true); - } - - String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME); - Activity activity = getActivity(); - PackageInfo packageInfo = getPackageInfo(activity, packageName); - if (packageInfo == null) { - Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show(); - activity.finish(); - return; - } - - mAppPermissions = new AppPermissions(activity, packageInfo, true, new Runnable() { - @Override - public void run() { - getActivity().finish(); - } - }); - updatePreferences(); - } - - @Override - public void onResume() { - super.onResume(); - mAppPermissions.refresh(); - updatePreferences(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: { - getActivity().finish(); - return true; - } - - case MENU_ALL_PERMS: { - showAllPermissions(null); - return true; - } - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - if (mAppPermissions != null) { - bindUi(this, mAppPermissions.getPackageInfo()); - } - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - menu.add(Menu.NONE, MENU_ALL_PERMS, Menu.NONE, R.string.all_permissions); - HelpUtils.prepareHelpMenuItem(getActivity(), menu, R.string.help_app_permissions, - getClass().getName()); - } - - private void showAllPermissions(String filterGroup) { - Fragment frag = AllAppPermissionsFragment.newInstance( - getArguments().getString(Intent.EXTRA_PACKAGE_NAME), - filterGroup); - getFragmentManager().beginTransaction() - .replace(android.R.id.content, frag) - .addToBackStack("AllPerms") - .commit(); - } - - private static void bindUi(SettingsWithHeader fragment, PackageInfo packageInfo) { - Activity activity = fragment.getActivity(); - PackageManager pm = activity.getPackageManager(); - ApplicationInfo appInfo = packageInfo.applicationInfo; - Intent infoIntent = null; - if (!activity.getIntent().getBooleanExtra(EXTRA_HIDE_INFO_BUTTON, false)) { - infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) - .setData(Uri.fromParts("package", packageInfo.packageName, null)); - } - - Drawable icon = IconDrawableFactory.newInstance(activity).getBadgedIcon(appInfo); - CharSequence label = appInfo.loadLabel(pm); - fragment.setHeader(icon, label, infoIntent); - - ActionBar ab = activity.getActionBar(); - if (ab != null) { - ab.setTitle(R.string.app_permissions); - } - } - - private void updatePreferences() { - Context context = getActivity(); - if (context == null) { - return; - } - - PreferenceScreen screen = getPreferenceScreen(); - if (screen == null) { - screen = getPreferenceManager().createPreferenceScreen(getActivity()); - setPreferenceScreen(screen); - } - - screen.removeAll(); - - if (mExtraScreen != null) { - mExtraScreen.removeAll(); - } - - final Preference extraPerms = new Preference(context); - extraPerms.setIcon(R.drawable.ic_toc); - extraPerms.setTitle(R.string.additional_permissions); - - for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { - if (!Utils.shouldShowPermission(group)) { - continue; - } - - boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG); - - PermissionPreference preference = new PermissionPreference(this, group, this); - preference.setKey(group.getName()); - Drawable icon = Utils.loadDrawable(context.getPackageManager(), - group.getIconPkg(), group.getIconResId()); - preference.setIcon(Utils.applyTint(getContext(), icon, - android.R.attr.colorControlNormal)); - preference.setTitle(group.getLabel()); - - if (isPlatform) { - screen.addPreference(preference); - } else { - if (mExtraScreen == null) { - mExtraScreen = getPreferenceManager().createPreferenceScreen(context); - } - mExtraScreen.addPreference(preference); - } - } - - if (mExtraScreen != null) { - extraPerms.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - AdditionalPermissionsFragment frag = new AdditionalPermissionsFragment(); - setPackageName(frag, getArguments().getString(Intent.EXTRA_PACKAGE_NAME)); - frag.setTargetFragment(AppPermissionsFragment.this, 0); - getFragmentManager().beginTransaction() - .replace(android.R.id.content, frag) - .addToBackStack(null) - .commit(); - return true; - } - }); - int count = mExtraScreen.getPreferenceCount(); - extraPerms.setSummary(getResources().getQuantityString( - R.plurals.additional_permissions_more, count, count)); - screen.addPreference(extraPerms); - } - - setLoading(false /* loading */, true /* animate */); - } - - @Override - public void onPreferenceChanged(String key) { - if (mToggledGroups == null) { - mToggledGroups = new ArraySet<>(); - } - mToggledGroups.add(mAppPermissions.getPermissionGroup(key)); - } - - @Override - public void onPause() { - super.onPause(); - logToggledGroups(); - } - - private void logToggledGroups() { - if (mToggledGroups != null) { - SafetyNetLogger.logPermissionsToggled(mToggledGroups); - mToggledGroups = null; - } - } - - private static PackageInfo getPackageInfo(Activity activity, String packageName) { - try { - return activity.getPackageManager().getPackageInfo( - packageName, PackageManager.GET_PERMISSIONS); - } catch (PackageManager.NameNotFoundException e) { - Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e); - return null; - } - } - - @Override - public boolean shouldConfirmDefaultPermissionRevoke() { - return !mHasConfirmedRevoke; - } - - @Override - public void hasConfirmDefaultPermissionRevoke() { - mHasConfirmedRevoke = true; - } - - @Override - public void onBackgroundAccessChosen(String key, int chosenItem) { - ((PermissionPreference) getPreferenceScreen().findPreference(key)) - .onBackgroundAccessChosen(chosenItem); - } - - @Override - public void onDenyAnyWay(String key, @PermissionPreference.ChangeTarget int changeTarget) { - ((PermissionPreference) getPreferenceScreen().findPreference(key)).onDenyAnyWay( - changeTarget); - } - - public static class AdditionalPermissionsFragment extends SettingsWithHeader { - AppPermissionsFragment mOuterFragment; - - @Override - public void onCreate(Bundle savedInstanceState) { - mOuterFragment = (AppPermissionsFragment) getTargetFragment(); - super.onCreate(savedInstanceState); - setHeader(mOuterFragment.mIcon, mOuterFragment.mLabel, mOuterFragment.mInfoIntent); - setHasOptionsMenu(true); - setPreferenceScreen(mOuterFragment.mExtraScreen); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME); - bindUi(this, getPackageInfo(getActivity(), packageName)); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - getFragmentManager().popBackStack(); - return true; - } - return super.onOptionsItemSelected(item); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.java deleted file mode 100644 index a9e5fc7f341131b83642cb520b3c064da9973e3c..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.java +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui.handheld; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.app.Activity; -import android.content.Intent; -import android.graphics.drawable.Icon; -import android.os.Bundle; -import android.transition.ChangeBounds; -import android.transition.Transition; -import android.transition.TransitionManager; -import android.transition.TransitionSet; -import android.transition.TransitionValues; -import android.transition.Visibility; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.WindowManager.LayoutParams; -import android.view.accessibility.AccessibilityNodeInfo; -import android.view.animation.AnimationUtils; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.ImageView; -import android.widget.RadioButton; -import android.widget.RadioGroup; -import android.widget.Space; -import android.widget.TextView; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.ui.ButtonBarLayout; -import com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler; -import com.android.packageinstaller.permission.ui.ManagePermissionsActivity; -import com.android.packageinstaller.permission.ui.ManualLayoutFrame; - -public class GrantPermissionsViewHandlerImpl implements GrantPermissionsViewHandler, - OnClickListener, RadioGroup.OnCheckedChangeListener { - - public static final String ARG_GROUP_NAME = "ARG_GROUP_NAME"; - public static final String ARG_GROUP_COUNT = "ARG_GROUP_COUNT"; - public static final String ARG_GROUP_INDEX = "ARG_GROUP_INDEX"; - public static final String ARG_GROUP_ICON = "ARG_GROUP_ICON"; - public static final String ARG_GROUP_MESSAGE = "ARG_GROUP_MESSAGE"; - private static final String ARG_GROUP_DETAIL_MESSAGE = "ARG_GROUP_DETAIL_MESSAGE"; - - public static final String ARG_GROUP_SHOW_DO_NOT_ASK = "ARG_GROUP_SHOW_DO_NOT_ASK"; - private static final String ARG_GROUP_SHOW_FOREGOUND_CHOOSER = - "ARG_GROUP_SHOW_FOREGOUND_CHOOSER"; - - public static final String ARG_GROUP_DO_NOT_ASK_CHECKED = "ARG_GROUP_DO_NOT_ASK_CHECKED"; - private static final String ARG_GROUP_ALWAYS_OPTION_CHECKED = "ARG_GROUP_ALWAYS_OPTION_CHECKED"; - - // Animation parameters. - private static final long SWITCH_TIME_MILLIS = 75; - private static final long ANIMATION_DURATION_MILLIS = 200; - - private final Activity mActivity; - private final String mAppPackageName; - private final boolean mPermissionsIndividuallyControlled; - - private ResultListener mResultListener; - - // Configuration of the current dialog - private String mGroupName; - private int mGroupCount; - private int mGroupIndex; - private Icon mGroupIcon; - private CharSequence mGroupMessage; - private CharSequence mDetailMessage; - - private boolean mShowDonNotAsk; - private boolean mShowForegroundChooser; - - // Views - private ImageView mIconView; - private TextView mCurrentGroupView; - private TextView mMessageView; - private TextView mDetailMessageView; - private CheckBox mDoNotAskCheckbox; - private RadioGroup mForegroundChooser; - private RadioButton mForegroundOnlyOption; - private RadioButton mAlwaysOption; - private RadioButton mDenyAndDontAskAgainOption; - private Button mAllowButton; - private Button mMoreInfoButton; - private ManualLayoutFrame mRootView; - private ViewGroup mContentContainer; - private Space mSpacer; - - public GrantPermissionsViewHandlerImpl(Activity activity, String appPackageName) { - mActivity = activity; - mAppPackageName = appPackageName; - mPermissionsIndividuallyControlled = - activity.getPackageManager().arePermissionsIndividuallyControlled(); - } - - @Override - public GrantPermissionsViewHandlerImpl setResultListener(ResultListener listener) { - mResultListener = listener; - return this; - } - - @Override - public void saveInstanceState(Bundle arguments) { - arguments.putString(ARG_GROUP_NAME, mGroupName); - arguments.putInt(ARG_GROUP_COUNT, mGroupCount); - arguments.putInt(ARG_GROUP_INDEX, mGroupIndex); - arguments.putParcelable(ARG_GROUP_ICON, mGroupIcon); - arguments.putCharSequence(ARG_GROUP_MESSAGE, mGroupMessage); - arguments.putCharSequence(ARG_GROUP_DETAIL_MESSAGE, mDetailMessage); - - arguments.putBoolean(ARG_GROUP_SHOW_DO_NOT_ASK, mShowDonNotAsk); - arguments.putBoolean(ARG_GROUP_SHOW_FOREGOUND_CHOOSER, mShowForegroundChooser); - - arguments.putBoolean(ARG_GROUP_DO_NOT_ASK_CHECKED, isDoNotAskAgainChecked()); - arguments.putBoolean(ARG_GROUP_ALWAYS_OPTION_CHECKED, mAlwaysOption.isSelected()); - } - - @Override - public void loadInstanceState(Bundle savedInstanceState) { - mGroupName = savedInstanceState.getString(ARG_GROUP_NAME); - mGroupMessage = savedInstanceState.getCharSequence(ARG_GROUP_MESSAGE); - mGroupIcon = savedInstanceState.getParcelable(ARG_GROUP_ICON); - mGroupCount = savedInstanceState.getInt(ARG_GROUP_COUNT); - mGroupIndex = savedInstanceState.getInt(ARG_GROUP_INDEX); - mDetailMessage = savedInstanceState.getCharSequence(ARG_GROUP_DETAIL_MESSAGE); - - mShowDonNotAsk = savedInstanceState.getBoolean(ARG_GROUP_SHOW_DO_NOT_ASK); - mShowForegroundChooser = savedInstanceState.getBoolean(ARG_GROUP_SHOW_FOREGOUND_CHOOSER); - - updateAll(savedInstanceState.getBoolean(ARG_GROUP_DO_NOT_ASK_CHECKED), - savedInstanceState.getBoolean(ARG_GROUP_ALWAYS_OPTION_CHECKED)); - } - - @Override - public void updateUi(String groupName, int groupCount, int groupIndex, Icon icon, - CharSequence message, CharSequence detailMessage, boolean showForegroundChooser, - boolean showDonNotAsk) { - boolean isNewGroup = mGroupIndex != groupIndex; - boolean isDoNotAskAgainChecked = mDoNotAskCheckbox.isChecked(); - boolean isAlwaysOptionChecked = mAlwaysOption.isChecked(); - if (isNewGroup) { - isDoNotAskAgainChecked = false; - isAlwaysOptionChecked = false; - } - - mGroupName = groupName; - mGroupCount = groupCount; - mGroupIndex = groupIndex; - mGroupIcon = icon; - mGroupMessage = message; - mShowDonNotAsk = showDonNotAsk; - mDetailMessage = detailMessage; - mShowForegroundChooser = showForegroundChooser; - - // If this is a second (or later) permission and the views exist, then animate. - if (mIconView != null) { - if (isNewGroup) { - animateToPermission(isDoNotAskAgainChecked, isAlwaysOptionChecked); - } else { - updateAll(isDoNotAskAgainChecked, isAlwaysOptionChecked); - } - } - } - - private void updateAll(boolean isDoNotAskAgainChecked, boolean isAlwaysOptionChecked) { - updateDescription(); - updateDetailDescription(); - updateGroup(); - updateDoNotAskCheckBoxAndForegroundOption(isDoNotAskAgainChecked, isAlwaysOptionChecked); - } - - private void animateToPermission(boolean isDoNotAskAgainChecked, - boolean isAlwaysOptionChecked) { - final View newContent = bindNewContent(); - - updateDescription(); - updateDetailDescription(); - updateDoNotAskCheckBoxAndForegroundOption(isDoNotAskAgainChecked, isAlwaysOptionChecked); - // Update group when the content changes (in onAppear below) - - final View oldView = mContentContainer.getChildAt(0); - - // Grow or shrink the content container to size of new content - ChangeBounds growShrinkToNewContentSize = new ChangeBounds(); - growShrinkToNewContentSize.setDuration(ANIMATION_DURATION_MILLIS); - growShrinkToNewContentSize.setInterpolator(AnimationUtils.loadInterpolator(mActivity, - android.R.interpolator.fast_out_slow_in)); - - // With a delay hide the old content and show the new content - Visibility changeContent = new Visibility() { - @Override - public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, - TransitionValues endValues) { - view.setVisibility(View.INVISIBLE); - - ValueAnimator v = ValueAnimator.ofFloat(0, 1); - - v.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - view.setVisibility(View.VISIBLE); - updateGroup(); - } - }); - - return v; - } - - @Override - public Animator onDisappear(ViewGroup sceneRoot, final View view, - TransitionValues startValues, TransitionValues endValues) { - ValueAnimator v = ValueAnimator.ofFloat(0, 1); - - int[] location = new int[2]; - // The removed view is put into the overlay that is relative to the window. Hence - // it does not get moved along with the changing parent view. This is done manually - // here. - v.addUpdateListener(animation -> { - mContentContainer.getLocationInWindow(location); - view.setTop(location[1]); - }); - - return v; - } - }; - changeContent.setDuration(SWITCH_TIME_MILLIS); - - TransitionSet combinedAnimation = new TransitionSet(); - combinedAnimation.addTransition(growShrinkToNewContentSize); - combinedAnimation.addTransition(changeContent); - combinedAnimation.setOrdering(TransitionSet.ORDERING_TOGETHER); - combinedAnimation.setMatchOrder(Transition.MATCH_INSTANCE); - - TransitionManager.beginDelayedTransition(mRootView, combinedAnimation); - mContentContainer.removeView(oldView); - mContentContainer.addView(newContent); - } - - /** - * Update this objects fields to point to the a content view. A content view encapsulates the - * permission request message, the detail message, the always deny checkbox, and the foreground - * chooser. - * - * @return The new content view - */ - private View bindNewContent() { - ViewGroup content = (ViewGroup) LayoutInflater.from(mActivity) - .inflate(R.layout.grant_permissions_content, mContentContainer, false); - - mMessageView = content.requireViewById(R.id.permission_message); - mDetailMessageView = content.requireViewById(R.id.detail_message); - mIconView = content.requireViewById(R.id.permission_icon); - mDoNotAskCheckbox = content.requireViewById(R.id.do_not_ask_checkbox); - mSpacer = content.requireViewById(R.id.detail_message_do_not_ask_checkbox_space); - mForegroundChooser = content.requireViewById(R.id.foreground_or_always_radiogroup); - mForegroundOnlyOption = content.requireViewById(R.id.foreground_only_radio_button); - mAlwaysOption = content.requireViewById(R.id.always_radio_button); - mDenyAndDontAskAgainOption = content.requireViewById(R.id.deny_dont_ask_again_radio_button); - - mDoNotAskCheckbox.setOnClickListener(this); - mDenyAndDontAskAgainOption.setOnClickListener(this); - mForegroundChooser.setOnCheckedChangeListener(this); - - return content; - } - - @Override - public View createView() { - mRootView = (ManualLayoutFrame) LayoutInflater.from(mActivity) - .inflate(R.layout.grant_permissions, null); - mContentContainer = mRootView.requireViewById(R.id.content_container); - mContentContainer.removeAllViews(); - mContentContainer.addView(bindNewContent()); - - mCurrentGroupView = (TextView) mRootView.findViewById(R.id.current_page_text); - mAllowButton = (Button) mRootView.findViewById(R.id.permission_allow_button); - mAllowButton.setOnClickListener(this); - - if (mPermissionsIndividuallyControlled) { - mMoreInfoButton = (Button) mRootView.findViewById(R.id.permission_more_info_button); - mMoreInfoButton.setVisibility(View.VISIBLE); - mMoreInfoButton.setOnClickListener(this); - } - - mRootView.findViewById(R.id.permission_deny_button).setOnClickListener(this); - - ((ButtonBarLayout) mRootView.requireViewById(R.id.button_group)).setAllowStacking(true); - - if (mGroupName != null) { - updateAll(false, false); - } - - return mRootView; - } - - @Override - public void updateWindowAttributes(LayoutParams outLayoutParams) { - // No-op - } - - private void updateDescription() { - if (mGroupIcon != null) { - mIconView.setImageDrawable(mGroupIcon.loadDrawable(mActivity)); - } - mMessageView.setText(mGroupMessage); - } - - private void updateDetailDescription() { - if (mDetailMessage == null) { - mDetailMessageView.setVisibility(View.GONE); - mSpacer.setVisibility(View.GONE); - } else { - if (mShowDonNotAsk) { - mSpacer.setVisibility(View.VISIBLE); - } else { - mSpacer.setVisibility(View.GONE); - } - - mDetailMessageView.setText(mDetailMessage); - mDetailMessageView.setVisibility(View.VISIBLE); - } - } - - private void updateGroup() { - if (mGroupCount > 1) { - mCurrentGroupView.setVisibility(View.VISIBLE); - mCurrentGroupView.setText(mActivity.getString(R.string.current_permission_template, - mGroupIndex + 1, mGroupCount)); - } else { - mCurrentGroupView.setVisibility(View.GONE); - } - } - - private void updateDoNotAskCheckBoxAndForegroundOption(boolean isDoNotAskAgainChecked, - boolean isAlwaysSelected) { - if (mShowForegroundChooser) { - mForegroundChooser.setVisibility(View.VISIBLE); - mDoNotAskCheckbox.setVisibility(View.GONE); - - if (isAlwaysSelected) { - mAlwaysOption.setSelected(true); - } - - if (mShowDonNotAsk) { - mDenyAndDontAskAgainOption.setSelected(isDoNotAskAgainChecked); - mDenyAndDontAskAgainOption.setVisibility(View.VISIBLE); - } else { - mDenyAndDontAskAgainOption.setVisibility(View.GONE); - } - } else { - mForegroundChooser.setVisibility(View.GONE); - if (mShowDonNotAsk) { - mDoNotAskCheckbox.setVisibility(View.VISIBLE); - mDoNotAskCheckbox.setChecked(isDoNotAskAgainChecked); - } else { - mDoNotAskCheckbox.setVisibility(View.GONE); - } - } - - mAllowButton.setEnabled(!isDoNotAskAgainChecked() && isOptionChosenIfNeeded()); - } - - private boolean isDoNotAskAgainChecked() { - return (mDoNotAskCheckbox.getVisibility() == View.VISIBLE - && mDoNotAskCheckbox.isChecked()) - || (mDenyAndDontAskAgainOption.getVisibility() == View.VISIBLE - && mDenyAndDontAskAgainOption.isChecked()); - } - - private boolean isOptionChosenIfNeeded() { - return !mShowForegroundChooser - || (mForegroundOnlyOption.isChecked() - || (mDenyAndDontAskAgainOption.getVisibility() == View.VISIBLE - && mDenyAndDontAskAgainOption.isChecked()) - || (mAlwaysOption.getVisibility() == View.VISIBLE && mAlwaysOption.isChecked())); - } - - @Override - public void onClick(View view) { - switch (view.getId()) { - case R.id.permission_allow_button: - if (mResultListener != null) { - view.performAccessibilityAction( - AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); - if (mShowForegroundChooser && mForegroundOnlyOption.isChecked()) { - mResultListener.onPermissionGrantResult(mGroupName, - GRANTED_FOREGROUND_ONLY); - } else { - mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ALWAYS); - } - } - break; - case R.id.permission_deny_button: - if (mResultListener != null) { - view.performAccessibilityAction( - AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); - if (isDoNotAskAgainChecked()) { - mResultListener.onPermissionGrantResult(mGroupName, - DENIED_DO_NOT_ASK_AGAIN); - } else { - mResultListener.onPermissionGrantResult(mGroupName, DENIED); - } - } - break; - case R.id.permission_more_info_button: - Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS); - intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mAppPackageName); - intent.putExtra(ManagePermissionsActivity.EXTRA_ALL_PERMISSIONS, true); - mActivity.startActivity(intent); - break; - } - - mAllowButton.setEnabled(!isDoNotAskAgainChecked() && isOptionChosenIfNeeded()); - - } - - @Override - public void onBackPressed() { - if (mResultListener != null) { - mResultListener.onPermissionGrantResult(mGroupName, DENIED); - } - } - - @Override - public void onCheckedChanged(RadioGroup group, int checkedId) { - mAllowButton.setEnabled(!isDoNotAskAgainChecked() && isOptionChosenIfNeeded()); - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/ManageCustomPermissionsFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/ManageCustomPermissionsFragment.java deleted file mode 100644 index 4f740e2c0cfd65e5c4e8c2ba93d6e72a90e83572..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/ManageCustomPermissionsFragment.java +++ /dev/null @@ -1,46 +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.handheld; - -import android.view.MenuItem; - -/** - * Fragment that allows the user to manage custom permissions. - */ -public class ManageCustomPermissionsFragment extends ManagePermissionsFragment { - @Override - public void onStart() { - super.onStart(); - - getActivity().setTitle(com.android.packageinstaller.R.string.additional_permissions); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - getFragmentManager().popBackStack(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - protected void updatePermissionsUi() { - updatePermissionsUi(false); - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/ManagePermissionsFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/ManagePermissionsFragment.java deleted file mode 100644 index e50a1d89ff76ee7b93c96d754810d926ff69e881..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/ManagePermissionsFragment.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.packageinstaller.permission.ui.handheld; - -import android.app.ActionBar; -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.preference.Preference; -import android.preference.PreferenceScreen; -import android.util.ArraySet; -import android.util.Log; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.PermissionApps.PmCache; -import com.android.packageinstaller.permission.model.PermissionGroup; -import com.android.packageinstaller.permission.model.PermissionGroups; -import com.android.packageinstaller.permission.utils.Utils; - -import java.util.List; - -/** - * Superclass for fragments allowing the user to manage permissions. - */ -abstract class ManagePermissionsFragment extends PermissionsFrameFragment - implements PermissionGroups.PermissionsGroupsChangeCallback, - Preference.OnPreferenceClickListener { - private static final String LOG_TAG = "ManagePermissionsFragment"; - - static final String OS_PKG = "android"; - - private ArraySet<String> mLauncherPkgs; - - private PermissionGroups mPermissions; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - setLoading(true /* loading */, false /* animate */); - setHasOptionsMenu(true); - final ActionBar ab = getActivity().getActionBar(); - if (ab != null) { - ab.setDisplayHomeAsUpEnabled(true); - } - mLauncherPkgs = Utils.getLauncherPackages(getContext()); - mPermissions = new PermissionGroups(getContext(), getLoaderManager(), this); - } - - @Override - public boolean onPreferenceClick(Preference preference) { - String key = preference.getKey(); - - PermissionGroup group = mPermissions.getGroup(key); - if (group == null) { - return false; - } - - Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSION_APPS) - .putExtra(Intent.EXTRA_PERMISSION_NAME, key); - try { - getActivity().startActivity(intent); - } catch (ActivityNotFoundException e) { - Log.w(LOG_TAG, "No app to handle " + intent); - } - - return true; - } - - /** - * @return the permissions - */ - protected PermissionGroups getPermissions() { - return mPermissions; - } - - @Override - public void onPermissionGroupsChanged() { - updatePermissionsUi(); - } - - /** - * Update the preferences to show the new {@link #getPermissions() permissions}. - */ - protected abstract void updatePermissionsUi(); - - /** - * Add preferences for all permissions of a type to the preference screen. - * - * @param addSystemPermissions If the permissions added should be system permissions or not - * - * @return The preference screen the permissions were added to - */ - protected PreferenceScreen updatePermissionsUi(boolean addSystemPermissions) { - Context context = getActivity(); - if (context == null) { - return null; - } - - List<PermissionGroup> groups = mPermissions.getGroups(); - PreferenceScreen screen = getPreferenceScreen(); - if (screen == null) { - screen = getPreferenceManager().createPreferenceScreen(getActivity()); - setPreferenceScreen(screen); - } else { - screen.removeAll(); - } - - // Use this to speed up getting the info for all of the PermissionApps below. - // Create a new one for each refresh to make sure it has fresh data. - PmCache cache = new PmCache(getContext().getPackageManager()); - for (PermissionGroup group : groups) { - boolean isSystemPermission = group.getDeclaringPackage().equals(OS_PKG); - - if (addSystemPermissions == isSystemPermission) { - Preference preference = findPreference(group.getName()); - - if (preference == null) { - preference = new Preference(context); - preference.setOnPreferenceClickListener(this); - preference.setKey(group.getName()); - preference.setIcon(Utils.applyTint(context, group.getIcon(), - android.R.attr.colorControlNormal)); - preference.setTitle(group.getLabel()); - // Set blank summary so that no resizing/jumping happens when the summary is - // loaded. - preference.setSummary(" "); - preference.setPersistent(false); - screen.addPreference(preference); - } - preference.setSummary(getString(R.string.app_permissions_group_summary, - group.getGranted(), group.getTotal())); - } - } - if (screen.getPreferenceCount() != 0) { - setLoading(false /* loading */, true /* animate */); - } - - return screen; - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/ManageStandardPermissionsFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/ManageStandardPermissionsFragment.java deleted file mode 100644 index 075ab3ce609e9a2a934e4be54ed670032801d9fd..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/ManageStandardPermissionsFragment.java +++ /dev/null @@ -1,107 +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.handheld; - -import android.app.FragmentTransaction; -import android.preference.Preference; -import android.preference.PreferenceScreen; -import android.view.MenuItem; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.PermissionGroup; -import com.android.packageinstaller.permission.utils.Utils; - -import java.util.List; - -/** - * Fragment that allows the user to manage standard permissions. - */ -public final class ManageStandardPermissionsFragment extends ManagePermissionsFragment { - private static final String EXTRA_PREFS_KEY = "extra_prefs_key"; - - /** - * @return A new fragment - */ - public static ManageStandardPermissionsFragment newInstance() { - return new ManageStandardPermissionsFragment(); - } - - @Override - public void onStart() { - super.onStart(); - - getActivity().setTitle(com.android.packageinstaller.R.string.app_permissions); - } - - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - getActivity().finish(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - protected void updatePermissionsUi() { - PreferenceScreen screen = updatePermissionsUi(true); - if (screen == null) { - return; - } - - // Check if we need an additional permissions preference - List<PermissionGroup> groups = getPermissions().getGroups(); - int numExtraPermissions = 0; - for (PermissionGroup group : groups) { - if (!group.getDeclaringPackage().equals(ManagePermissionsFragment.OS_PKG)) { - numExtraPermissions++; - } - } - - Preference additionalPermissionsPreference = screen.findPreference(EXTRA_PREFS_KEY); - if (numExtraPermissions == 0) { - if (additionalPermissionsPreference != null) { - screen.removePreference(additionalPermissionsPreference); - } - } else { - if (additionalPermissionsPreference == null) { - additionalPermissionsPreference = new Preference(getActivity()); - additionalPermissionsPreference.setKey(EXTRA_PREFS_KEY); - additionalPermissionsPreference.setIcon(Utils.applyTint(getActivity(), - R.drawable.ic_more_items, - android.R.attr.colorControlNormal)); - additionalPermissionsPreference.setTitle(R.string.additional_permissions); - additionalPermissionsPreference.setOnPreferenceClickListener(preference -> { - ManageCustomPermissionsFragment frag = - new ManageCustomPermissionsFragment(); - frag.setTargetFragment(ManageStandardPermissionsFragment.this, 0); - FragmentTransaction ft = getFragmentManager().beginTransaction(); - ft.replace(android.R.id.content, frag); - ft.addToBackStack(null); - ft.commit(); - return true; - }); - - screen.addPreference(additionalPermissionsPreference); - } - - additionalPermissionsPreference.setSummary(getResources().getQuantityString( - R.plurals.additional_permissions_more, numExtraPermissions, - numExtraPermissions)); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/MultiTargetSwitchPreference.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/MultiTargetSwitchPreference.java deleted file mode 100644 index dfd721a29d6c9bc301f0c591268575cd29b678aa..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/MultiTargetSwitchPreference.java +++ /dev/null @@ -1,60 +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.handheld; - -import android.content.Context; -import android.preference.SwitchPreference; -import android.view.View; -import android.widget.Switch; - -class MultiTargetSwitchPreference extends SwitchPreference { - private View.OnClickListener mSwitchOnClickLister; - - public MultiTargetSwitchPreference(Context context) { - super(context); - } - - public void setCheckedOverride(boolean checked) { - super.setChecked(checked); - } - - @Override - public void setChecked(boolean checked) { - // If double target behavior is enabled do nothing - if (mSwitchOnClickLister == null) { - super.setChecked(checked); - } - } - - public void setSwitchOnClickListener(View.OnClickListener listener) { - mSwitchOnClickLister = listener; - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - Switch switchView = (Switch) view.findViewById( - com.android.internal.R.id.switch_widget); - switchView.setOnClickListener(mSwitchOnClickLister); - - if (mSwitchOnClickLister != null) { - final int padding = (int) ((view.getMeasuredHeight() - - switchView.getMeasuredHeight()) / 2 + 0.5f); - switchView.setPadding(padding, padding, 0, padding); - } - } -} \ No newline at end of file diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java deleted file mode 100644 index b2a37ac53214d1a7733946259c8d9e707d1c4bc5..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.packageinstaller.permission.ui.handheld; - -import android.app.ActionBar; -import android.app.Fragment; -import android.content.Context; -import android.content.Intent; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.preference.Preference; -import android.preference.Preference.OnPreferenceClickListener; -import android.preference.PreferenceScreen; -import android.preference.SwitchPreference; -import android.util.ArraySet; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; - -import com.android.packageinstaller.DeviceUtils; -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.PermissionApps; -import com.android.packageinstaller.permission.model.PermissionApps.Callback; -import com.android.packageinstaller.permission.model.PermissionApps.PermissionApp; -import com.android.packageinstaller.permission.utils.SafetyNetLogger; -import com.android.packageinstaller.permission.utils.Utils; -import com.android.settingslib.HelpUtils; - -/** - * Show and manage apps which request a single permission group. - * - * <p>Shows a list of apps which request at least on permission of this group. - */ -public final class PermissionAppsFragment extends PermissionsFrameFragment implements Callback, - PermissionPreference.PermissionPreferenceOwnerFragment, - PermissionPreference.PermissionPreferenceChangeListener { - - private static final int MENU_SHOW_SYSTEM = Menu.FIRST; - private static final int MENU_HIDE_SYSTEM = Menu.FIRST + 1; - private static final String KEY_SHOW_SYSTEM_PREFS = "_showSystem"; - - private static final String SHOW_SYSTEM_KEY = PermissionAppsFragment.class.getName() - + KEY_SHOW_SYSTEM_PREFS; - - public static PermissionAppsFragment newInstance(String permissionName) { - return setPermissionName(new PermissionAppsFragment(), permissionName); - } - - private static <T extends Fragment> T setPermissionName(T fragment, String permissionName) { - Bundle arguments = new Bundle(); - arguments.putString(Intent.EXTRA_PERMISSION_NAME, permissionName); - fragment.setArguments(arguments); - return fragment; - } - - private PermissionApps mPermissionApps; - - private PreferenceScreen mExtraScreen; - - private ArraySet<AppPermissionGroup> mToggledGroups; - private ArraySet<String> mLauncherPkgs; - private boolean mHasConfirmedRevoke; - - private boolean mShowSystem; - private boolean mHasSystemApps; - private MenuItem mShowSystemMenu; - private MenuItem mHideSystemMenu; - - private Callback mOnPermissionsLoadedListener; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if (savedInstanceState != null) { - mShowSystem = savedInstanceState.getBoolean(SHOW_SYSTEM_KEY); - } - - setLoading(true /* loading */, false /* animate */); - setHasOptionsMenu(true); - final ActionBar ab = getActivity().getActionBar(); - if (ab != null) { - ab.setDisplayHomeAsUpEnabled(true); - } - mLauncherPkgs = Utils.getLauncherPackages(getContext()); - - String groupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME); - mPermissionApps = new PermissionApps(getActivity(), groupName, this); - mPermissionApps.refresh(true); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - outState.putBoolean(SHOW_SYSTEM_KEY, mShowSystem); - } - - @Override - public void onResume() { - super.onResume(); - mPermissionApps.refresh(true); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - 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()); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - getActivity().finish(); - return true; - case MENU_SHOW_SYSTEM: - case MENU_HIDE_SYSTEM: - mShowSystem = item.getItemId() == MENU_SHOW_SYSTEM; - if (mPermissionApps.getApps() != null) { - onPermissionsLoaded(mPermissionApps); - } - updateMenu(); - break; - } - return super.onOptionsItemSelected(item); - } - - private void updateMenu() { - mShowSystemMenu.setVisible(!mShowSystem); - mHideSystemMenu.setVisible(mShowSystem); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - bindUi(this, mPermissionApps); - } - - private static void bindUi(Fragment fragment, PermissionApps permissionApps) { - final Drawable icon = permissionApps.getIcon(); - final CharSequence label = permissionApps.getLabel(); - final ActionBar ab = fragment.getActivity().getActionBar(); - if (ab != null) { - ab.setTitle(label); - } - } - - private void setOnPermissionsLoadedListener(Callback callback) { - mOnPermissionsLoadedListener = callback; - } - - @Override - public void onPermissionsLoaded(PermissionApps permissionApps) { - Context context = getActivity(); - - if (context == null) { - return; - } - - boolean isTelevision = DeviceUtils.isTelevision(context); - PreferenceScreen screen = getPreferenceScreen(); - if (screen == null) { - screen = getPreferenceManager().createPreferenceScreen(getActivity()); - setPreferenceScreen(screen); - } - - screen.setOrderingAsAdded(false); - - ArraySet<String> preferencesToRemove = new ArraySet<>(); - for (int i = 0, n = screen.getPreferenceCount(); i < n; i++) { - preferencesToRemove.add(screen.getPreference(i).getKey()); - } - if (mExtraScreen != null) { - for (int i = 0, n = mExtraScreen.getPreferenceCount(); i < n; i++) { - preferencesToRemove.add(mExtraScreen.getPreference(i).getKey()); - } - } - - mHasSystemApps = false; - boolean menuOptionsInvalided = false; - - for (PermissionApp app : permissionApps.getApps()) { - if (!Utils.shouldShowPermission(app.getPermissionGroup())) { - continue; - } - - if (!app.getAppInfo().enabled) { - continue; - } - - String key = app.getKey(); - preferencesToRemove.remove(key); - Preference existingPref = screen.findPreference(key); - if (existingPref == null && mExtraScreen != null) { - existingPref = mExtraScreen.findPreference(key); - } - - boolean isSystemApp = Utils.isSystem(app, mLauncherPkgs); - - if (isSystemApp && !menuOptionsInvalided) { - mHasSystemApps = true; - getActivity().invalidateOptionsMenu(); - menuOptionsInvalided = true; - } - - if (isSystemApp && !isTelevision && !mShowSystem) { - if (existingPref != null) { - screen.removePreference(existingPref); - } - continue; - } - - if (existingPref != null) { - ((PermissionPreference) existingPref).updateUi(); - continue; - } - - PermissionPreference pref = new PermissionPreference(this, app.getPermissionGroup(), - this); - pref.setKey(app.getKey()); - pref.setIcon(app.getIcon()); - pref.setTitle(app.getLabel()); - - if (isSystemApp && isTelevision) { - if (mExtraScreen == null) { - mExtraScreen = getPreferenceManager().createPreferenceScreen(context); - } - mExtraScreen.addPreference(pref); - } else { - screen.addPreference(pref); - } - } - - if (mExtraScreen != null) { - preferencesToRemove.remove(KEY_SHOW_SYSTEM_PREFS); - Preference pref = screen.findPreference(KEY_SHOW_SYSTEM_PREFS); - - if (pref == null) { - pref = new Preference(context); - pref.setKey(KEY_SHOW_SYSTEM_PREFS); - pref.setIcon(Utils.applyTint(context, R.drawable.ic_toc, - android.R.attr.colorControlNormal)); - pref.setTitle(R.string.preference_show_system_apps); - pref.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - SystemAppsFragment frag = new SystemAppsFragment(); - setPermissionName(frag, getArguments().getString(Intent.EXTRA_PERMISSION_NAME)); - frag.setTargetFragment(PermissionAppsFragment.this, 0); - getFragmentManager().beginTransaction() - .replace(android.R.id.content, frag) - .addToBackStack("SystemApps") - .commit(); - return true; - } - }); - screen.addPreference(pref); - } - - int grantedCount = 0; - for (int i = 0, n = mExtraScreen.getPreferenceCount(); i < n; i++) { - if (((SwitchPreference) mExtraScreen.getPreference(i)).isChecked()) { - grantedCount++; - } - } - pref.setSummary(getString(R.string.app_permissions_group_summary, - grantedCount, mExtraScreen.getPreferenceCount())); - } - - for (String key : preferencesToRemove) { - Preference pref = screen.findPreference(key); - if (pref != null) { - screen.removePreference(pref); - } else if (mExtraScreen != null) { - pref = mExtraScreen.findPreference(key); - if (pref != null) { - mExtraScreen.removePreference(pref); - } - } - } - - setLoading(false /* loading */, true /* animate */); - - if (mOnPermissionsLoadedListener != null) { - mOnPermissionsLoadedListener.onPermissionsLoaded(permissionApps); - } - } - - @Override - public void onPreferenceChanged(String key) { - if (mToggledGroups == null) { - mToggledGroups = new ArraySet<>(); - } - mToggledGroups.add(mPermissionApps.getApp(key).getPermissionGroup()); - } - - @Override - public void onPause() { - super.onPause(); - logToggledGroups(); - } - - private void logToggledGroups() { - if (mToggledGroups != null) { - SafetyNetLogger.logPermissionsToggled(mToggledGroups); - mToggledGroups = null; - } - } - - @Override - public void onBackgroundAccessChosen(String key, int chosenItem) { - ((PermissionPreference) getPreferenceScreen().findPreference(key)) - .onBackgroundAccessChosen(chosenItem); - } - - @Override - public void onDenyAnyWay(String key, @PermissionPreference.ChangeTarget int changeTarget) { - ((PermissionPreference) getPreferenceScreen().findPreference(key)).onDenyAnyWay( - changeTarget); - } - - @Override - public boolean shouldConfirmDefaultPermissionRevoke() { - return !mHasConfirmedRevoke; - } - - @Override - public void hasConfirmDefaultPermissionRevoke() { - mHasConfirmedRevoke = true; - } - - public static class SystemAppsFragment extends PermissionsFrameFragment implements Callback { - PermissionAppsFragment mOuterFragment; - - @Override - public void onCreate(Bundle savedInstanceState) { - mOuterFragment = (PermissionAppsFragment) getTargetFragment(); - setLoading(true /* loading */, false /* animate */); - super.onCreate(savedInstanceState); - if (mOuterFragment.mExtraScreen != null) { - setPreferenceScreen(); - } else { - mOuterFragment.setOnPermissionsLoadedListener(this); - } - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - String groupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME); - PermissionApps permissionApps = new PermissionApps(getActivity(), groupName, null); - bindUi(this, permissionApps); - } - - @Override - public void onPermissionsLoaded(PermissionApps permissionApps) { - setPreferenceScreen(); - mOuterFragment.setOnPermissionsLoadedListener(null); - } - - private void setPreferenceScreen() { - setPreferenceScreen(mOuterFragment.mExtraScreen); - setLoading(false /* loading */, true /* animate */); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/PermissionPreference.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/PermissionPreference.java deleted file mode 100644 index 8563705b4f9ada73c86d0feb187a0ee533c2bf72..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/PermissionPreference.java +++ /dev/null @@ -1,581 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui.handheld; - -import static com.android.packageinstaller.permission.utils.Utils.getRequestMessage; - -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.app.Fragment; -import android.content.DialogInterface; -import android.content.pm.PackageItemInfo; -import android.os.Bundle; -import android.text.BidiFormatter; -import android.widget.Switch; - -import androidx.annotation.IntDef; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.Permission; -import com.android.packageinstaller.permission.utils.LocationUtils; -import com.android.packageinstaller.permission.utils.Utils; -import com.android.settingslib.RestrictedLockUtils; - -import java.lang.annotation.Retention; -import java.util.List; - -/** - * A preference for representing a permission group requested by an app. - */ -class PermissionPreference extends RestrictedSwitchPreference { - @Retention(SOURCE) - @IntDef(value = {CHANGE_FOREGROUND, CHANGE_BACKGROUND}, flag = true) - @interface ChangeTarget {} - static final int CHANGE_FOREGROUND = 1; - static final int CHANGE_BACKGROUND = 2; - static final int CHANGE_BOTH = CHANGE_FOREGROUND | CHANGE_BACKGROUND; - - private final AppPermissionGroup mGroup; - private final Fragment mFragment; - private final PermissionPreferenceChangeListener mCallBacks; - - /** Callbacks for the permission to the fragment showing a list of permissions */ - interface PermissionPreferenceChangeListener { - /** - * Checks if the user has to confirm a revocation of a permission granted by default. - * - * @return {@code true} iff the user has to confirm it - */ - boolean shouldConfirmDefaultPermissionRevoke(); - - /** - * Notify the listener that the user confirmed that she/he wants to revoke permissions that - * were granted by default. - */ - void hasConfirmDefaultPermissionRevoke(); - - /** - * Notify the listener that this preference has changed. - * - * @param key The key uniquely identifying this preference - */ - void onPreferenceChanged(String key); - } - - /** - * Callbacks from dialogs to the fragment. These callbacks are supposed to directly cycle back - * to the permission tha created the dialog. - */ - interface PermissionPreferenceOwnerFragment { - /** - * The {@link DefaultDenyDialog} can only interact with the fragment, not the preference - * that created it. Hence this call goes to the fragment, which then finds the preference an - * calls {@link #onDenyAnyWay(int)}. - * - * @param key Key uniquely identifying the preference that created the default deny dialog - * @param changeTarget Whether background or foreground permissions should be changed - * - * @see #showDefaultDenyDialog(int) - */ - void onDenyAnyWay(String key, @ChangeTarget int changeTarget); - - /** - * The {@link BackgroundAccessChooser} can only interact with the fragment, not the - * preference that created it. Hence this call goes to the fragment, which then finds the - * preference an calls {@link #onBackgroundAccessChosen(int)}}. - * - * @param key Key uniquely identifying the preference that created the background access - * chooser - * @param chosenItem The index of the item selected by the user. - * - * @see #showBackgroundChooserDialog() - */ - void onBackgroundAccessChosen(String key, int chosenItem); - } - - PermissionPreference(Fragment fragment, AppPermissionGroup group, - PermissionPreferenceChangeListener callbacks) { - super(fragment.getContext()); - - mFragment = fragment; - mGroup = group; - mCallBacks = callbacks; - - setPersistent(false); - updateUi(); - } - - /** - * Update the preference after the state might have changed. - */ - void updateUi() { - boolean arePermissionsIndividuallyControlled = - Utils.areGroupPermissionsIndividuallyControlled(getContext(), mGroup.getName()); - RestrictedLockUtils.EnforcedAdmin admin = - RestrictedLockUtils.getProfileOrDeviceOwner(getContext(), mGroup.getUserId()); - boolean isForegroundPolicyFixed = mGroup.isPolicyFixed(); - boolean isBackgroundPolicyFixed = mGroup.getBackgroundPermissions() == null - || mGroup.getBackgroundPermissions().isPolicyFixed(); - boolean isAdminFixed = admin != null; - boolean isPolicyFixed = (isForegroundPolicyFixed && isBackgroundPolicyFixed) - && !isAdminFixed; - - // Reset ui state - setDisabledByAdmin(null); - setEnabled(true); - setOnPreferenceClickListener(null); - setSwitchOnClickListener(null); - setSummary(null); - - setChecked(mGroup.areRuntimePermissionsGranted()); - - if (isAdminFixed) { - setDisabledByAdmin(admin); - setSummary(R.string.permission_summary_enforced_by_admin); - setEnabled(false); - } else if (isPolicyFixed) { - // Both foreground and background filed - setSummary(R.string.permission_summary_enforced_by_policy); - setEnabled(false); - } else if (arePermissionsIndividuallyControlled) { - setOnPreferenceClickListener((pref) -> { - showAllPermissions(mGroup.getName()); - return false; - }); - - setSwitchOnClickListener(v -> { - Switch switchView = (Switch) v; - requestChange(switchView.isChecked(), CHANGE_BOTH); - - // Update UI as the switch widget might be in wrong state - updateUi(); - }); - - updateSummaryForIndividuallyControlledPermissionGroup(); - } else { - if (mGroup.hasPermissionWithBackgroundMode()) { - if (mGroup.getBackgroundPermissions() == null) { - // The group has background permissions but the app did not request any. I.e. - // The app can only switch between 'never" and "only in foreground". - setOnPreferenceChangeListener((pref, newValue) -> - requestChange((Boolean) newValue, CHANGE_FOREGROUND)); - - updateSummaryForPermissionGroupWithBackgroundPermission(); - } else { - AppPermissionGroup backgroundGroup = mGroup.getBackgroundPermissions(); - - if (isBackgroundPolicyFixed) { - setOnPreferenceChangeListener((pref, newValue) -> - requestChange((Boolean) newValue, CHANGE_FOREGROUND)); - - if (backgroundGroup.areRuntimePermissionsGranted()) { - setSummary(R.string - .permission_summary_enabled_by_policy_background_only); - } else { - setSummary(R.string - .permission_summary_disabled_by_policy_background_only); - } - } else if (isForegroundPolicyFixed) { - if (mGroup.areRuntimePermissionsGranted()) { - setOnPreferenceChangeListener((pref, newValue) -> - requestChange((Boolean) newValue, CHANGE_BACKGROUND)); - - setSummary(R.string - .permission_summary_enabled_by_policy_foreground_only); - } else { - // Background access can only be enabled once foreground access is - // enabled. Hence if foreground access can never be enabled, there is - // no point allowing background access to be enabled - setSummary(R.string.permission_summary_enforced_by_policy); - setEnabled(false); - } - } else { - updateSummaryForPermissionGroupWithBackgroundPermission(); - - setOnPreferenceClickListener((pref) -> { - showBackgroundChooserDialog(); - return true; - }); - - setSwitchOnClickListener(v -> { - Switch switchView = (Switch) v; - - if (switchView.isChecked()) { - showBackgroundChooserDialog(); - } else { - requestChange(false, CHANGE_BOTH); - } - - // Update UI as the switch widget might be in wrong state - updateUi(); - }); - } - } - } else { - setOnPreferenceChangeListener((pref, newValue) -> - requestChange((Boolean) newValue, CHANGE_BOTH)); - } - } - } - - /** - * Update the summary in the case the permission group has individually controlled permissions. - */ - private void updateSummaryForIndividuallyControlledPermissionGroup() { - int revokedCount = 0; - List<Permission> permissions = mGroup.getPermissions(); - final int permissionCount = permissions.size(); - for (int i = 0; i < permissionCount; i++) { - Permission permission = permissions.get(i); - if (mGroup.doesSupportRuntimePermissions() - ? !permission.isGranted() : (!permission.isAppOpAllowed() - || permission.isReviewRequired())) { - revokedCount++; - } - } - - final int resId; - if (revokedCount == 0) { - resId = R.string.permission_revoked_none; - } else if (revokedCount == permissionCount) { - resId = R.string.permission_revoked_all; - } else { - resId = R.string.permission_revoked_count; - } - - String summary = getContext().getString(resId, revokedCount); - setSummary(summary); - } - - /** - * Update the summary of a permission group that has background permission. - * - * <p>This does not apply to permission groups that are fixed by policy</p> - */ - private void updateSummaryForPermissionGroupWithBackgroundPermission() { - AppPermissionGroup backgroundGroup = mGroup.getBackgroundPermissions(); - - if (mGroup.areRuntimePermissionsGranted()) { - if (backgroundGroup == null) { - setSummary(R.string.permission_access_only_foreground); - } else { - if (backgroundGroup.areRuntimePermissionsGranted()) { - setSummary(R.string.permission_access_always); - } else { - setSummary(R.string.permission_access_only_foreground); - } - } - } else { - setSummary(R.string.permission_access_never); - } - } - - /** - * Show all individual permissions in this group in a new fragment. - */ - private void showAllPermissions(String filterGroup) { - Fragment frag = AllAppPermissionsFragment.newInstance(mGroup.getApp().packageName, - filterGroup); - mFragment.getFragmentManager().beginTransaction() - .replace(android.R.id.content, frag) - .addToBackStack("AllPerms") - .commit(); - } - - /** - * Get the label of the app the permission group belongs to. (App permission groups are all - * permissions of a group an app has requested.) - * - * @return The label of the app - */ - private String getAppLabel() { - return BidiFormatter.getInstance().unicodeWrap( - mGroup.getApp().applicationInfo.loadSafeLabel(getContext().getPackageManager(), - PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX, - PackageItemInfo.SAFE_LABEL_FLAG_TRIM - | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE) - .toString()); - } - - /** - * Request to grant/revoke permissions group. - * - * <p>Does <u>not</u> handle: - * <ul> - * <li>Individually granted permissions</li> - * <li>Permission groups with background permissions</li> - * </ul> - * <p><u>Does</u> handle: - * <ul> - * <li>Default grant permissions</li> - * </ul> - * - * @param requestGrant If this group should be granted - * @param changeTarget Which permission group (foreground/background/both) should be changed - * @return If the request was processed. - */ - private boolean requestChange(boolean requestGrant, @ChangeTarget int changeTarget) { - if (LocationUtils.isLocationGroupAndProvider(mGroup.getName(), - mGroup.getApp().packageName)) { - LocationUtils.showLocationDialog(getContext(), getAppLabel()); - return false; - } - if (requestGrant) { - mCallBacks.onPreferenceChanged(getKey()); - - if ((changeTarget & CHANGE_FOREGROUND) != 0) { - mGroup.grantRuntimePermissions(false); - } - if ((changeTarget & CHANGE_BACKGROUND) != 0) { - if (mGroup.getBackgroundPermissions() != null) { - mGroup.getBackgroundPermissions().grantRuntimePermissions(false); - } - } - } else { - boolean requestToRevokeGrantedByDefault = false; - if ((changeTarget & CHANGE_FOREGROUND) != 0) { - requestToRevokeGrantedByDefault = mGroup.hasGrantedByDefaultPermission(); - } - if ((changeTarget & CHANGE_BACKGROUND) != 0) { - if (mGroup.getBackgroundPermissions() != null) { - requestToRevokeGrantedByDefault |= - mGroup.getBackgroundPermissions().hasGrantedByDefaultPermission(); - } - } - - if ((requestToRevokeGrantedByDefault || !mGroup.doesSupportRuntimePermissions()) - && mCallBacks.shouldConfirmDefaultPermissionRevoke()) { - showDefaultDenyDialog(changeTarget); - return false; - } else { - mCallBacks.onPreferenceChanged(getKey()); - - if ((changeTarget & CHANGE_FOREGROUND) != 0) { - mGroup.revokeRuntimePermissions(false); - } - if ((changeTarget & CHANGE_BACKGROUND) != 0) { - if (mGroup.getBackgroundPermissions() != null) { - mGroup.getBackgroundPermissions().revokeRuntimePermissions(false); - } - } - } - } - - updateUi(); - - return true; - } - - /** - * Show a dialog that warns the user that she/he is about to revoke permissions that were - * granted by default. - * - * <p>The order of operation to revoke a permission granted by default is: - * <ol> - * <li>{@code showDefaultDenyDialog}</li> - * <li>{@link DefaultDenyDialog#onCreateDialog}</li> - * <li>{@link PermissionPreferenceOwnerFragment#onDenyAnyWay}</li> - * <li>{@link PermissionPreference#onDenyAnyWay}</li> - * </ol> - * - * @param changeTarget Whether background or foreground should be changed - */ - private void showDefaultDenyDialog(@ChangeTarget int changeTarget) { - Bundle args = new Bundle(); - - boolean showGrantedByDefaultWarning = false; - if ((changeTarget & CHANGE_FOREGROUND) != 0) { - showGrantedByDefaultWarning = mGroup.hasGrantedByDefaultPermission(); - } - if ((changeTarget & CHANGE_BACKGROUND) != 0) { - if (mGroup.getBackgroundPermissions() != null) { - showGrantedByDefaultWarning |= - mGroup.getBackgroundPermissions().hasGrantedByDefaultPermission(); - } - } - - args.putInt(DefaultDenyDialog.MSG, showGrantedByDefaultWarning ? R.string.system_warning - : R.string.old_sdk_deny_warning); - args.putString(DefaultDenyDialog.KEY, getKey()); - args.putInt(DefaultDenyDialog.CHANGE_TARGET, changeTarget); - - DefaultDenyDialog deaultDenyDialog = new DefaultDenyDialog(); - deaultDenyDialog.setArguments(args); - deaultDenyDialog.show(mFragment.getChildFragmentManager().beginTransaction(), - "denyDefault"); - } - - /** - * Show a dialog that asks the user if foreground/background/none access should be enabled. - * - * <p>The order of operation to grant foreground/background/none access is: - * <ol> - * <li>{@code showBackgroundChooserDialog}</li> - * <li>{@link BackgroundAccessChooser#onCreateDialog}</li> - * <li>{@link PermissionPreferenceOwnerFragment#onBackgroundAccessChosen}</li> - * <li>{@link PermissionPreference#onBackgroundAccessChosen}</li> - * </ol> - */ - private void showBackgroundChooserDialog() { - Bundle args = new Bundle(); - args.putCharSequence(BackgroundAccessChooser.TITLE, - getRequestMessage(getAppLabel(), mGroup, getContext(), mGroup.getRequest())); - args.putString(BackgroundAccessChooser.KEY, getKey()); - - - if (mGroup.areRuntimePermissionsGranted()) { - if (mGroup.getBackgroundPermissions().areRuntimePermissionsGranted()) { - args.putInt(BackgroundAccessChooser.SELECTION, - BackgroundAccessChooser.ALWAYS_OPTION); - } else { - args.putInt(BackgroundAccessChooser.SELECTION, - BackgroundAccessChooser.FOREGROUND_ONLY_OPTION); - } - } else { - args.putInt(BackgroundAccessChooser.SELECTION, BackgroundAccessChooser.NEVER_OPTION); - } - - BackgroundAccessChooser chooserDialog = new BackgroundAccessChooser(); - chooserDialog.setArguments(args); - chooserDialog.show(mFragment.getChildFragmentManager().beginTransaction(), - "backgroundChooser"); - } - - /** - * Once we user has confirmed that he/she wants to revoke a permission that was granted by - * default, actually revoke the permissions. - * - * @see #showDefaultDenyDialog(int) - */ - void onDenyAnyWay(@ChangeTarget int changeTarget) { - mCallBacks.onPreferenceChanged(getKey()); - - boolean hasDefaultPermissions = false; - if ((changeTarget & CHANGE_FOREGROUND) != 0) { - mGroup.revokeRuntimePermissions(false); - hasDefaultPermissions = mGroup.hasGrantedByDefaultPermission(); - } - if ((changeTarget & CHANGE_BACKGROUND) != 0) { - if (mGroup.getBackgroundPermissions() != null) { - mGroup.getBackgroundPermissions().revokeRuntimePermissions(false); - hasDefaultPermissions |= - mGroup.getBackgroundPermissions().hasGrantedByDefaultPermission(); - } - } - - if (hasDefaultPermissions) { - mCallBacks.hasConfirmDefaultPermissionRevoke(); - } - updateUi(); - } - - /** - * Process the return from a {@link BackgroundAccessChooser} dialog. - * - * <p>These dialog are started when the user want to grant a permission group that has - * background permissions. - * - * @param choosenItem The item that the user chose - */ - void onBackgroundAccessChosen(int choosenItem) { - AppPermissionGroup backgroundGroup = mGroup.getBackgroundPermissions(); - - switch (choosenItem) { - case BackgroundAccessChooser.ALWAYS_OPTION: - requestChange(true, CHANGE_BOTH); - break; - case BackgroundAccessChooser.FOREGROUND_ONLY_OPTION: - if (backgroundGroup.areRuntimePermissionsGranted()) { - requestChange(false, CHANGE_BACKGROUND); - } - requestChange(true, CHANGE_FOREGROUND); - break; - case BackgroundAccessChooser.NEVER_OPTION: - if (mGroup.areRuntimePermissionsGranted() - || mGroup.getBackgroundPermissions().areRuntimePermissionsGranted()) { - requestChange(false, CHANGE_BOTH); - } - break; - } - } - - /** - * A dialog warning the user that she/he is about to deny a permission that was granted by - * default. - * - * @see #showDefaultDenyDialog(int) - */ - public static class DefaultDenyDialog extends DialogFragment { - private static final String MSG = DefaultDenyDialog.class.getName() + ".arg.msg"; - private static final String CHANGE_TARGET = DefaultDenyDialog.class.getName() - + ".arg.changeTarget"; - private static final String KEY = DefaultDenyDialog.class.getName() + ".arg.key"; - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - AlertDialog.Builder b = new AlertDialog.Builder(getContext()) - .setMessage(getArguments().getInt(MSG)) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.grant_dialog_button_deny_anyway, - (DialogInterface dialog, int which) -> ( - (PermissionPreferenceOwnerFragment) getParentFragment()) - .onDenyAnyWay(getArguments().getString(KEY), - getArguments().getInt(CHANGE_TARGET))); - - return b.create(); - } - } - - /** - * If a permission group has background permission this chooser is used to let the user - * choose how the permission group should be granted. - * - * @see #showBackgroundChooserDialog() - */ - public static class BackgroundAccessChooser extends DialogFragment { - private static final String TITLE = BackgroundAccessChooser.class.getName() + ".arg.title"; - private static final String KEY = BackgroundAccessChooser.class.getName() + ".arg.key"; - private static final String SELECTION = BackgroundAccessChooser.class.getName() - + ".arg.selection"; - - // Needs to match the entries in R.array.background_access_chooser_dialog_choices - static final int ALWAYS_OPTION = 0; - static final int FOREGROUND_ONLY_OPTION = 1; - static final int NEVER_OPTION = 2; - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - AlertDialog.Builder b = new AlertDialog.Builder(getActivity()) - .setTitle(getArguments().getCharSequence(TITLE)) - .setSingleChoiceItems(R.array.background_access_chooser_dialog_choices, - getArguments().getInt(SELECTION), - (dialog, which) -> { - dismissAllowingStateLoss(); - ((PermissionPreferenceOwnerFragment) getParentFragment()) - .onBackgroundAccessChosen(getArguments().getString(KEY), - which); - } - ); - - return b.create(); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/PermissionsFrameFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/PermissionsFrameFragment.java deleted file mode 100644 index e7f63b2387ff4bde3860a94940eb99e8ab71a39f..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/PermissionsFrameFragment.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui.handheld; - -import android.os.Bundle; -import android.preference.PreferenceFragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.Animation; -import android.view.animation.Animation.AnimationListener; -import android.view.animation.AnimationUtils; -import android.widget.ListView; -import android.widget.TextView; -import com.android.packageinstaller.R; - -public abstract class PermissionsFrameFragment extends PreferenceFragment { - private ViewGroup mPreferencesContainer; - - private View mLoadingView; - private ViewGroup mPrefsView; - private boolean mIsLoading; - - /** - * Returns the view group that holds the preferences objects. This will - * only be set after {@link #onCreateView} has been called. - */ - protected final ViewGroup getPreferencesContainer() { - return mPreferencesContainer; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.permissions_frame, container, - false); - mPrefsView = (ViewGroup) rootView.findViewById(R.id.prefs_container); - if (mPrefsView == null) { - mPrefsView = rootView; - } - mLoadingView = rootView.findViewById(R.id.loading_container); - mPreferencesContainer = (ViewGroup) super.onCreateView( - inflater, mPrefsView, savedInstanceState); - setLoading(mIsLoading, false, true /* force */); - mPrefsView.addView(mPreferencesContainer); - return rootView; - } - - protected void setLoading(boolean loading, boolean animate) { - setLoading(loading, animate, false); - } - - private void setLoading(boolean loading, boolean animate, boolean force) { - if (mIsLoading != loading || force) { - mIsLoading = loading; - if (getView() == null) { - // If there is no created view, there is no reason to animate. - animate = false; - } - if (mPrefsView != null) { - setViewShown(mPrefsView, !loading, animate); - } - if (mLoadingView != null) { - setViewShown(mLoadingView, loading, animate); - } - } - } - - @Override - public ListView getListView() { - ListView listView = super.getListView(); - if (listView.getEmptyView() == null) { - TextView emptyView = (TextView) getView().findViewById(R.id.no_permissions); - listView.setEmptyView(emptyView); - } - return listView; - } - - private void setViewShown(final View view, boolean shown, boolean animate) { - if (animate) { - Animation animation = AnimationUtils.loadAnimation(getContext(), - shown ? android.R.anim.fade_in : android.R.anim.fade_out); - if (shown) { - view.setVisibility(View.VISIBLE); - } else { - animation.setAnimationListener(new AnimationListener() { - @Override - public void onAnimationStart(Animation animation) { - } - - @Override - public void onAnimationRepeat(Animation animation) { - } - - @Override - public void onAnimationEnd(Animation animation) { - view.setVisibility(View.INVISIBLE); - } - }); - } - view.startAnimation(animation); - } else { - view.clearAnimation(); - view.setVisibility(shown ? View.VISIBLE : View.INVISIBLE); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/RestrictedSwitchPreference.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/RestrictedSwitchPreference.java deleted file mode 100644 index 30ccf3bfd56128a7fae80f49c27f2ff4dfa6e549..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/RestrictedSwitchPreference.java +++ /dev/null @@ -1,84 +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.handheld; - -import android.content.Context; -import android.preference.PreferenceScreen; -import android.view.View; -import android.widget.TextView; - -import com.android.packageinstaller.R; -import com.android.settingslib.RestrictedLockUtils; - -import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; - -public class RestrictedSwitchPreference extends MultiTargetSwitchPreference { - private final Context mContext; - private boolean mDisabledByAdmin; - private EnforcedAdmin mEnforcedAdmin; - private final int mSwitchWidgetResId; - - public RestrictedSwitchPreference(Context context) { - super(context); - mSwitchWidgetResId = getWidgetLayoutResource(); - mContext = context; - } - - @Override - public void onBindView(View view) { - super.onBindView(view); - if (mDisabledByAdmin) { - view.setEnabled(true); - } - if (mDisabledByAdmin) { - final TextView summaryView = (TextView) view.findViewById(android.R.id.summary); - if (summaryView != null) { - summaryView.setText( - isChecked() ? R.string.enabled_by_admin : R.string.disabled_by_admin); - summaryView.setVisibility(View.VISIBLE); - } - } - } - - @Override - public void setEnabled(boolean enabled) { - if (enabled && mDisabledByAdmin) { - setDisabledByAdmin(null); - } else { - super.setEnabled(enabled); - } - } - - public void setDisabledByAdmin(EnforcedAdmin admin) { - final boolean disabled = (admin != null ? true : false); - mEnforcedAdmin = admin; - if (mDisabledByAdmin != disabled) { - mDisabledByAdmin = disabled; - setWidgetLayoutResource(disabled ? R.layout.restricted_icon : mSwitchWidgetResId); - setEnabled(!disabled); - } - } - - @Override - public void performClick(PreferenceScreen preferenceScreen) { - if (mDisabledByAdmin) { - RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, mEnforcedAdmin); - } else { - super.performClick(preferenceScreen); - } - } -} \ No newline at end of file diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/ReviewPermissionsFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/ReviewPermissionsFragment.java deleted file mode 100644 index 83fef0dbc13f35f227b3a9324864c35b03f5221e..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/ReviewPermissionsFragment.java +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui.handheld; - -import android.app.Activity; -import android.content.Intent; -import android.content.IntentSender; -import android.content.pm.PackageInfo; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.RemoteCallback; -import android.text.Html; -import android.text.Spanned; -import android.view.View; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.fragment.app.DialogFragment; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceFragmentCompat; -import androidx.preference.PreferenceGroup; -import androidx.preference.PreferenceScreen; -import androidx.preference.SwitchPreference; -import androidx.preference.TwoStatePreference; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.AppPermissions; -import com.android.packageinstaller.permission.model.Permission; -import com.android.packageinstaller.permission.ui.ConfirmActionDialogFragment; -import com.android.packageinstaller.permission.ui.ManagePermissionsActivity; -import com.android.packageinstaller.permission.utils.ArrayUtils; -import com.android.packageinstaller.permission.utils.Utils; - -import java.util.ArrayList; -import java.util.List; - -public final class ReviewPermissionsFragment extends PreferenceFragmentCompat - implements View.OnClickListener, Preference.OnPreferenceChangeListener, - ConfirmActionDialogFragment.OnActionConfirmedListener { - - private static final String EXTRA_PACKAGE_INFO = - "com.android.packageinstaller.permission.ui.extra.PACKAGE_INFO"; - - private AppPermissions mAppPermissions; - - private Button mContinueButton; - private Button mCancelButton; - private Button mMoreInfoButton; - - private PreferenceCategory mNewPermissionsCategory; - private PreferenceCategory mCurrentPermissionsCategory; - - private boolean mHasConfirmedRevoke; - - public static ReviewPermissionsFragment newInstance(PackageInfo packageInfo) { - Bundle arguments = new Bundle(); - arguments.putParcelable(ReviewPermissionsFragment.EXTRA_PACKAGE_INFO, packageInfo); - ReviewPermissionsFragment instance = new ReviewPermissionsFragment(); - instance.setArguments(arguments); - instance.setRetainInstance(true); - return instance; - } - - @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - Activity activity = getActivity(); - if (activity == null) { - return; - } - - PackageInfo packageInfo = getArguments().getParcelable(EXTRA_PACKAGE_INFO); - if (packageInfo == null) { - activity.finish(); - return; - } - - mAppPermissions = new AppPermissions(activity, packageInfo, false, - () -> getActivity().finish()); - - if (mAppPermissions.getPermissionGroups().isEmpty()) { - activity.finish(); - return; - } - - boolean reviewRequired = false; - for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { - if (group.isReviewRequired()) { - reviewRequired = true; - break; - } - } - - if (!reviewRequired) { - activity.finish(); - } - } - - @Override - public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - bindUi(); - } - - @Override - public void onResume() { - super.onResume(); - mAppPermissions.refresh(); - loadPreferences(); - } - - @Override - public void onClick(View view) { - Activity activity = getActivity(); - if (activity == null) { - return; - } - if (view == mContinueButton) { - confirmPermissionsReview(); - executeCallback(true); - } else if (view == mCancelButton) { - executeCallback(false); - activity.setResult(Activity.RESULT_CANCELED); - } else if (view == mMoreInfoButton) { - Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS); - intent.putExtra(Intent.EXTRA_PACKAGE_NAME, - mAppPermissions.getPackageInfo().packageName); - intent.putExtra(ManagePermissionsActivity.EXTRA_ALL_PERMISSIONS, true); - getActivity().startActivity(intent); - } - activity.finish(); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (mHasConfirmedRevoke) { - return true; - } - if (preference instanceof SwitchPreference) { - SwitchPreference switchPreference = (SwitchPreference) preference; - if (switchPreference.isChecked()) { - showWarnRevokeDialog(switchPreference.getKey()); - } else { - return true; - } - } - return false; - } - - @Override - public void onActionConfirmed(String action) { - Preference preference = getPreferenceManager().findPreference(action); - if (preference instanceof SwitchPreference) { - SwitchPreference switchPreference = (SwitchPreference) preference; - switchPreference.setChecked(false); - mHasConfirmedRevoke = true; - } - } - - private void showWarnRevokeDialog(final String groupName) { - DialogFragment fragment = ConfirmActionDialogFragment.newInstance( - getString(R.string.old_sdk_deny_warning), groupName); - fragment.show(getActivity().getSupportFragmentManager(), fragment.getClass().getName()); - } - - private void grantReviewedPermission(AppPermissionGroup group) { - String[] permissionsToGrant = null; - final int permissionCount = group.getPermissions().size(); - for (int j = 0; j < permissionCount; j++) { - final Permission permission = group.getPermissions().get(j); - if (permission.isReviewRequired()) { - permissionsToGrant = ArrayUtils.appendString( - permissionsToGrant, permission.getName()); - } - } - if (permissionsToGrant != null) { - group.grantRuntimePermissions(false, permissionsToGrant); - } - } - - private void confirmPermissionsReview() { - final List<PreferenceGroup> preferenceGroups = new ArrayList<>(); - if (mNewPermissionsCategory != null) { - preferenceGroups.add(mNewPermissionsCategory); - preferenceGroups.add(mCurrentPermissionsCategory); - } else { - preferenceGroups.add(getPreferenceScreen()); - } - - final int preferenceGroupCount = preferenceGroups.size(); - for (int groupNum = 0; groupNum < preferenceGroupCount; groupNum++) { - final PreferenceGroup preferenceGroup = preferenceGroups.get(groupNum); - - final int preferenceCount = preferenceGroup.getPreferenceCount(); - for (int prefNum = 0; prefNum < preferenceCount; prefNum++) { - Preference preference = preferenceGroup.getPreference(prefNum); - if (preference instanceof TwoStatePreference) { - TwoStatePreference twoStatePreference = (TwoStatePreference) preference; - String groupName = preference.getKey(); - AppPermissionGroup group = mAppPermissions.getPermissionGroup(groupName); - if (twoStatePreference.isChecked()) { - grantReviewedPermission(group); - - // TODO: Allow the user to only grant foreground permissions - if (group.getBackgroundPermissions() != null) { - grantReviewedPermission(group.getBackgroundPermissions()); - } - } else { - group.revokeRuntimePermissions(false); - if (group.getBackgroundPermissions() != null) { - group.getBackgroundPermissions().revokeRuntimePermissions(false); - } - } - group.resetReviewRequired(); - } - } - } - } - - private void bindUi() { - Activity activity = getActivity(); - if (activity == null) { - return; - } - - // Set icon - Drawable icon = mAppPermissions.getPackageInfo().applicationInfo.loadIcon( - activity.getPackageManager()); - ImageView iconView = activity.requireViewById(R.id.app_icon); - iconView.setImageDrawable(icon); - - // Set message - final int labelTemplateResId = isPackageUpdated() - ? R.string.permission_review_title_template_update - : R.string.permission_review_title_template_install; - Spanned message = Html.fromHtml(getString(labelTemplateResId, - mAppPermissions.getAppLabel()), 0); - - // Set the permission message as the title so it can be announced. - activity.setTitle(message.toString()); - - // Color the app name. - TextView permissionsMessageView = activity.requireViewById( - R.id.permissions_message); - permissionsMessageView.setText(message); - - mContinueButton = getActivity().requireViewById(R.id.continue_button); - mContinueButton.setOnClickListener(this); - - mCancelButton = getActivity().requireViewById(R.id.cancel_button); - mCancelButton.setOnClickListener(this); - - if (activity.getPackageManager().arePermissionsIndividuallyControlled()) { - mMoreInfoButton = getActivity().requireViewById( - R.id.permission_more_info_button); - mMoreInfoButton.setOnClickListener(this); - mMoreInfoButton.setVisibility(View.VISIBLE); - } - } - - private void loadPreferences() { - Activity activity = getActivity(); - if (activity == null) { - return; - } - - PreferenceScreen screen = getPreferenceScreen(); - if (screen == null) { - screen = getPreferenceManager().createPreferenceScreen(getActivity()); - setPreferenceScreen(screen); - } else { - screen.removeAll(); - } - - mCurrentPermissionsCategory = null; - PreferenceGroup oldNewPermissionsCategory = mNewPermissionsCategory; - mNewPermissionsCategory = null; - - final boolean isPackageUpdated = isPackageUpdated(); - - for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { - if (!Utils.shouldShowPermission(group) - || !Utils.OS_PKG.equals(group.getDeclaringPackage())) { - continue; - } - - final SwitchPreference preference; - Preference cachedPreference = oldNewPermissionsCategory != null - ? oldNewPermissionsCategory.findPreference(group.getName()) : null; - if (cachedPreference instanceof SwitchPreference) { - preference = (SwitchPreference) cachedPreference; - } else { - preference = new SwitchPreference(getActivity()); - - preference.setKey(group.getName()); - Drawable icon = Utils.loadDrawable(activity.getPackageManager(), - group.getIconPkg(), group.getIconResId()); - preference.setIcon(Utils.applyTint(getContext(), icon, - android.R.attr.colorControlNormal)); - preference.setTitle(group.getLabel()); - preference.setSummary(group.getDescription()); - preference.setPersistent(false); - - preference.setOnPreferenceChangeListener(this); - } - - preference.setChecked(group.areRuntimePermissionsGranted() - || group.isReviewRequired()); - - // Mutable state - if (group.isPolicyFixed()) { - preference.setEnabled(false); - preference.setSummary(getString( - R.string.permission_summary_enforced_by_policy)); - } else { - preference.setEnabled(true); - } - - if (group.isReviewRequired()) { - if (!isPackageUpdated) { - screen.addPreference(preference); - } else { - if (mNewPermissionsCategory == null) { - mNewPermissionsCategory = new PreferenceCategory(activity); - mNewPermissionsCategory.setTitle(R.string.new_permissions_category); - mNewPermissionsCategory.setOrder(1); - screen.addPreference(mNewPermissionsCategory); - } - mNewPermissionsCategory.addPreference(preference); - } - } else { - if (mCurrentPermissionsCategory == null) { - mCurrentPermissionsCategory = new PreferenceCategory(activity); - mCurrentPermissionsCategory.setTitle(R.string.current_permissions_category); - mCurrentPermissionsCategory.setOrder(2); - screen.addPreference(mCurrentPermissionsCategory); - } - mCurrentPermissionsCategory.addPreference(preference); - } - } - } - - private boolean isPackageUpdated() { - List<AppPermissionGroup> groups = mAppPermissions.getPermissionGroups(); - final int groupCount = groups.size(); - for (int i = 0; i < groupCount; i++) { - AppPermissionGroup group = groups.get(i); - if (!group.isReviewRequired()) { - return true; - } - } - return false; - } - - private void executeCallback(boolean success) { - Activity activity = getActivity(); - if (activity == null) { - return; - } - if (success) { - IntentSender intent = activity.getIntent().getParcelableExtra(Intent.EXTRA_INTENT); - if (intent != null) { - try { - int flagMask = 0; - int flagValues = 0; - if (activity.getIntent().getBooleanExtra( - Intent.EXTRA_RESULT_NEEDED, false)) { - flagMask = Intent.FLAG_ACTIVITY_FORWARD_RESULT; - flagValues = Intent.FLAG_ACTIVITY_FORWARD_RESULT; - } - activity.startIntentSenderForResult(intent, -1, null, - flagMask, flagValues, 0); - } catch (IntentSender.SendIntentException e) { - /* ignore */ - } - return; - } - } - RemoteCallback callback = activity.getIntent().getParcelableExtra( - Intent.EXTRA_REMOTE_CALLBACK); - if (callback != null) { - Bundle result = new Bundle(); - result.putBoolean(Intent.EXTRA_RETURN_RESULT, success); - callback.sendResult(result); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/SettingsWithHeader.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/SettingsWithHeader.java deleted file mode 100644 index d57757964a98681cebe60d39d209341fabea50f4..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/SettingsWithHeader.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui.handheld; - -import android.content.Intent; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import com.android.packageinstaller.DeviceUtils; -import com.android.packageinstaller.R; - -public abstract class SettingsWithHeader extends PermissionsFrameFragment - implements OnClickListener { - - private View mHeader; - protected Intent mInfoIntent; - protected Drawable mIcon; - protected CharSequence mLabel; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - ViewGroup root = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState); - - if (!DeviceUtils.isTelevision(getContext())) { - mHeader = inflater.inflate(R.layout.header, root, false); - getPreferencesContainer().addView(mHeader, 0); - updateHeader(); - } - - return root; - } - - public void setHeader(Drawable icon, CharSequence label, Intent infoIntent) { - mIcon = icon; - mLabel = label; - mInfoIntent = infoIntent; - updateHeader(); - } - - private void updateHeader() { - if (mHeader != null) { - final ImageView appIcon = (ImageView) mHeader.findViewById(R.id.icon); - appIcon.setImageDrawable(mIcon); - - final TextView appName = (TextView) mHeader.findViewById(R.id.name); - appName.setText(mLabel); - - final View info = mHeader.findViewById(R.id.info); - if (mInfoIntent == null) { - info.setVisibility(View.GONE); - } else { - info.setVisibility(View.VISIBLE); - info.setClickable(true); - info.setOnClickListener(this); - } - } - } - - @Override - public void onClick(View v) { - getActivity().startActivity(mInfoIntent); - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/AllAppPermissionsFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/AllAppPermissionsFragment.java deleted file mode 100644 index e56a1f7db537acc15ad9522ec6d99b53a19a65dd..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/AllAppPermissionsFragment.java +++ /dev/null @@ -1,319 +0,0 @@ -/* -* Copyright (C) 2015 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package com.android.packageinstaller.permission.ui.television; - -import android.Manifest; -import android.app.ActionBar; -import android.app.AlertDialog; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageItemInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.PermissionGroupInfo; -import android.content.pm.PermissionInfo; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.provider.Settings; -import android.util.Log; -import android.view.MenuItem; - -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.Preference.OnPreferenceClickListener; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceGroup; -import androidx.preference.SwitchPreference; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.AppPermissions; -import com.android.packageinstaller.permission.utils.Utils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; - -public final class AllAppPermissionsFragment extends SettingsWithHeader { - - private static final String LOG_TAG = "AllAppPermissionsFragment"; - - private static final String KEY_OTHER = "other_perms"; - - private PackageInfo mPackageInfo; - - private AppPermissions mAppPermissions; - - public static AllAppPermissionsFragment newInstance(String packageName) { - AllAppPermissionsFragment instance = new AllAppPermissionsFragment(); - Bundle arguments = new Bundle(); - arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName); - instance.setArguments(arguments); - return instance; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setHasOptionsMenu(true); - final ActionBar ab = getActivity().getActionBar(); - if (ab != null) { - ab.setTitle(R.string.all_permissions); - ab.setDisplayHomeAsUpEnabled(true); - } - - String pkg = getArguments().getString(Intent.EXTRA_PACKAGE_NAME); - try { - mPackageInfo = getActivity().getPackageManager().getPackageInfo(pkg, - PackageManager.GET_PERMISSIONS); - } catch (NameNotFoundException e) { - getActivity().finish(); - } - - mAppPermissions = new AppPermissions(getActivity(), mPackageInfo, false, - new Runnable() { - @Override - public void run() { - getActivity().finish(); - } - }); - } - - @Override - public void onResume() { - super.onResume(); - updateUi(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: { - getFragmentManager().popBackStack(); - return true; - } - } - return super.onOptionsItemSelected(item); - } - - private PreferenceGroup getOtherGroup() { - PreferenceGroup otherGroup = (PreferenceGroup) findPreference(KEY_OTHER); - if (otherGroup == null) { - otherGroup = new PreferenceCategory(getPreferenceManager().getContext()); - otherGroup.setKey(KEY_OTHER); - otherGroup.setTitle(getString(R.string.other_permissions)); - getPreferenceScreen().addPreference(otherGroup); - } - return otherGroup; - } - - private void updateUi() { - getPreferenceScreen().removeAll(); - - ArrayList<Preference> prefs = new ArrayList<>(); // Used for sorting. - PackageManager pm = getActivity().getPackageManager(); - - ApplicationInfo appInfo = mPackageInfo.applicationInfo; - final Drawable icon = appInfo.loadIcon(pm); - final CharSequence label = appInfo.loadLabel(pm); - Intent infoIntent = null; - if (!getActivity().getIntent().getBooleanExtra( - AppPermissionsFragment.EXTRA_HIDE_INFO_BUTTON, false)) { - infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) - .setData(Uri.fromParts("package", mPackageInfo.packageName, null)); - } - setHeader(icon, label, infoIntent, null); - - if (mPackageInfo.requestedPermissions != null) { - for (int i = 0; i < mPackageInfo.requestedPermissions.length; i++) { - PermissionInfo perm; - try { - perm = pm.getPermissionInfo(mPackageInfo.requestedPermissions[i], 0); - } catch (NameNotFoundException e) { - Log.e(LOG_TAG, "Can't get permission info for " - + mPackageInfo.requestedPermissions[i], e); - continue; - } - - if ((perm.flags & PermissionInfo.FLAG_INSTALLED) == 0 - || (perm.flags & PermissionInfo.FLAG_REMOVED) != 0) { - continue; - } - if (appInfo.isInstantApp() - && (perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) == 0) { - continue; - } - if (appInfo.targetSdkVersion < Build.VERSION_CODES.M - && (perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) - != 0) { - continue; - } - - - PermissionGroupInfo group = getGroup(perm.group, pm); - if ((perm.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) - == PermissionInfo.PROTECTION_DANGEROUS) { - PreferenceGroup pref = findOrCreate(group != null ? group : perm, pm, prefs); - pref.addPreference(getPreference(perm, group)); - } else if ((perm.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) - == PermissionInfo.PROTECTION_NORMAL) { - PreferenceGroup otherGroup = getOtherGroup(); - if (prefs.indexOf(otherGroup) < 0) { - prefs.add(otherGroup); - } - getOtherGroup().addPreference(getPreference(perm, group)); - } - } - } - - // Sort an ArrayList of the groups and then set the order from the sorting. - Collections.sort(prefs, new Comparator<Preference>() { - @Override - public int compare(Preference lhs, Preference rhs) { - String lKey = lhs.getKey(); - String rKey = rhs.getKey(); - if (lKey.equals(KEY_OTHER)) { - return 1; - } else if (rKey.equals(KEY_OTHER)) { - return -1; - } else if (Utils.isModernPermissionGroup(lKey) - != Utils.isModernPermissionGroup(rKey)) { - return Utils.isModernPermissionGroup(lKey) ? -1 : 1; - } - return lhs.getTitle().toString().compareTo(rhs.getTitle().toString()); - } - }); - for (int i = 0; i < prefs.size(); i++) { - prefs.get(i).setOrder(i); - } - } - - private PermissionGroupInfo getGroup(String group, PackageManager pm) { - try { - return pm.getPermissionGroupInfo(group, 0); - } catch (NameNotFoundException e) { - return null; - } - } - - private PreferenceGroup findOrCreate(PackageItemInfo group, PackageManager pm, - ArrayList<Preference> prefs) { - PreferenceGroup pref = (PreferenceGroup) findPreference(group.name); - if (pref == null) { - pref = new PreferenceCategory(getActivity()); - pref.setKey(group.name); - pref.setLayoutResource(R.layout.preference_category_material); - pref.setTitle(group.loadLabel(pm)); - prefs.add(pref); - getPreferenceScreen().addPreference(pref); - } - return pref; - } - - private Preference getPreference(final PermissionInfo perm, final PermissionGroupInfo group) { - if (isMutableGranularPermission(perm.name)) { - return getMutablePreference(perm, group); - } else { - return getImmutablePreference(perm, group); - } - } - - private Preference getMutablePreference(final PermissionInfo perm, PermissionGroupInfo group) { - final AppPermissionGroup permGroup = mAppPermissions.getPermissionGroup(group.name); - final String[] filterPermissions = new String[]{perm.name}; - - // TODO: No hardcoded layouts - SwitchPreference pref = new SwitchPreference(getPreferenceManager().getContext()); - pref.setLayoutResource(R.layout.preference_permissions); - pref.setChecked(permGroup.areRuntimePermissionsGranted(filterPermissions)); - pref.setIcon(getTintedPermissionIcon(getActivity(), perm, group)); - pref.setTitle(perm.loadLabel(getActivity().getPackageManager())); - pref.setPersistent(false); - - pref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object value) { - if (value == Boolean.TRUE) { - permGroup.grantRuntimePermissions(false, filterPermissions); - } else { - permGroup.revokeRuntimePermissions(false, filterPermissions); - } - return true; - } - }); - - return pref; - } - - private Preference getImmutablePreference(final PermissionInfo perm, - PermissionGroupInfo group) { - final PackageManager pm = getActivity().getPackageManager(); - - // TODO: No hardcoded layouts - Preference pref = new Preference(getActivity()); - pref.setLayoutResource(R.layout.preference_permissions); - pref.setIcon(getTintedPermissionIcon(getActivity(), perm, group)); - pref.setTitle(perm.loadLabel(pm)); - pref.setPersistent(false); - - pref.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - new AlertDialog.Builder(getActivity()) - .setMessage(perm.loadDescription(pm)) - .setPositiveButton(android.R.string.ok, null) - .show(); - return true; - } - }); - - return pref; - } - - private static Drawable getTintedPermissionIcon(Context context, PermissionInfo perm, - PermissionGroupInfo group) { - final Drawable icon; - if (perm.icon != 0) { - icon = perm.loadIcon(context.getPackageManager()); - } else if (group != null && group.icon != 0) { - icon = group.loadIcon(context.getPackageManager()); - } else { - icon = context.getDrawable(R.drawable.ic_perm_device_info); - } - return Utils.applyTint(context, icon, android.R.attr.colorControlNormal); - } - - private boolean isMutableGranularPermission(String name) { - if (!getContext().getPackageManager().arePermissionsIndividuallyControlled()) { - return false; - } - switch (name) { - case Manifest.permission.READ_CONTACTS: - case Manifest.permission.WRITE_CONTACTS: - case Manifest.permission.READ_SMS: - case Manifest.permission.READ_CALL_LOG: - case Manifest.permission.CALL_PHONE: { - return true; - } - } - return false; - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/AppPermissionsFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/AppPermissionsFragment.java deleted file mode 100644 index 442ee92876b1b1bfca6102a969537f2cbec4ef44..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/AppPermissionsFragment.java +++ /dev/null @@ -1,411 +0,0 @@ -/* -* Copyright (C) 2015 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package com.android.packageinstaller.permission.ui.television; - -import android.app.ActionBar; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Fragment; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Bundle; -import android.provider.Settings; -import android.util.ArraySet; -import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.Toast; - -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.PreferenceScreen; -import androidx.preference.PreferenceViewHolder; -import androidx.preference.SwitchPreference; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.AppPermissions; -import com.android.packageinstaller.permission.ui.ReviewPermissionsActivity; -import com.android.packageinstaller.permission.utils.LocationUtils; -import com.android.packageinstaller.permission.utils.SafetyNetLogger; -import com.android.packageinstaller.permission.utils.Utils; - -public final class AppPermissionsFragment extends SettingsWithHeader - implements OnPreferenceChangeListener { - - private static final String LOG_TAG = "ManagePermsFragment"; - - static final String EXTRA_HIDE_INFO_BUTTON = "hideInfoButton"; - - private static final int MENU_ALL_PERMS = 0; - - private ArraySet<AppPermissionGroup> mToggledGroups; - private AppPermissions mAppPermissions; - private PreferenceScreen mExtraScreen; - - private boolean mHasConfirmedRevoke; - - public static AppPermissionsFragment newInstance(String packageName) { - return setPackageName(new AppPermissionsFragment(), packageName); - } - - private static <T extends Fragment> T setPackageName(T fragment, String packageName) { - Bundle arguments = new Bundle(); - arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName); - fragment.setArguments(arguments); - return fragment; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setLoading(true /* loading */, false /* animate */); - setHasOptionsMenu(true); - final ActionBar ab = getActivity().getActionBar(); - if (ab != null) { - ab.setDisplayHomeAsUpEnabled(true); - } - - String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME); - Activity activity = getActivity(); - PackageInfo packageInfo = getPackageInfo(activity, packageName); - if (packageInfo == null) { - Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show(); - activity.finish(); - return; - } - - - mAppPermissions = new AppPermissions(activity, packageInfo, true, - () -> getActivity().finish()); - - if (mAppPermissions.isReviewRequired()) { - Intent intent = new Intent(getActivity(), ReviewPermissionsActivity.class); - intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName); - startActivity(intent); - getActivity().finish(); - return; - } - - loadPreferences(); - } - - @Override - public void onResume() { - super.onResume(); - mAppPermissions.refresh(); - loadPreferences(); - setPreferencesCheckedState(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: { - getActivity().finish(); - return true; - } - - case MENU_ALL_PERMS: { - Fragment frag = AllAppPermissionsFragment.newInstance( - getArguments().getString(Intent.EXTRA_PACKAGE_NAME)); - getFragmentManager().beginTransaction() - .replace(android.R.id.content, frag) - .addToBackStack("AllPerms") - .commit(); - return true; - } - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - if (mAppPermissions != null) { - bindUi(this, mAppPermissions.getPackageInfo()); - } - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - menu.add(Menu.NONE, MENU_ALL_PERMS, Menu.NONE, R.string.all_permissions); - } - - private static void bindUi(SettingsWithHeader fragment, PackageInfo packageInfo) { - Activity activity = fragment.getActivity(); - PackageManager pm = activity.getPackageManager(); - ApplicationInfo appInfo = packageInfo.applicationInfo; - Intent infoIntent = null; - if (!activity.getIntent().getBooleanExtra(EXTRA_HIDE_INFO_BUTTON, false)) { - infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) - .setData(Uri.fromParts("package", packageInfo.packageName, null)); - } - - Drawable icon = appInfo.loadIcon(pm); - CharSequence label = appInfo.loadLabel(pm); - fragment.setHeader(icon, label, infoIntent, fragment.getString( - R.string.app_permissions_decor_title)); - } - - private void loadPreferences() { - Context context = getPreferenceManager().getContext(); - if (context == null) { - return; - } - - PreferenceScreen screen = getPreferenceScreen(); - screen.removeAll(); - screen.addPreference(createHeaderLineTwoPreference(context)); - - if (mExtraScreen != null) { - mExtraScreen.removeAll(); - mExtraScreen = null; - } - - final Preference extraPerms = new Preference(context); - extraPerms.setIcon(R.drawable.ic_toc); - extraPerms.setTitle(R.string.additional_permissions); - - for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { - if (!Utils.shouldShowPermission(group)) { - continue; - } - - boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG); - - SwitchPreference preference = new SwitchPreference(context); - preference.setOnPreferenceChangeListener(this); - preference.setKey(group.getName()); - Drawable icon = Utils.loadDrawable(context.getPackageManager(), - group.getIconPkg(), group.getIconResId()); - preference.setIcon(Utils.applyTint(getContext(), icon, - android.R.attr.colorControlNormal)); - preference.setTitle(group.getLabel()); - if (group.isPolicyFixed()) { - preference.setSummary(getString(R.string.permission_summary_enforced_by_policy)); - } - preference.setPersistent(false); - preference.setEnabled(!group.isPolicyFixed()); - preference.setChecked(group.areRuntimePermissionsGranted()); - - if (isPlatform) { - screen.addPreference(preference); - } else { - if (mExtraScreen == null) { - mExtraScreen = getPreferenceManager().createPreferenceScreen(context); - mExtraScreen.addPreference(createHeaderLineTwoPreference(context)); - } - mExtraScreen.addPreference(preference); - } - } - - if (mExtraScreen != null) { - extraPerms.setOnPreferenceClickListener(preference -> { - AdditionalPermissionsFragment frag = new AdditionalPermissionsFragment(); - setPackageName(frag, getArguments().getString(Intent.EXTRA_PACKAGE_NAME)); - frag.setTargetFragment(AppPermissionsFragment.this, 0); - getFragmentManager().beginTransaction() - .replace(android.R.id.content, frag) - .addToBackStack(null) - .commit(); - return true; - }); - int count = mExtraScreen.getPreferenceCount() - 1; - extraPerms.setSummary(getResources().getQuantityString( - R.plurals.additional_permissions_more, count, count)); - screen.addPreference(extraPerms); - } - - setLoading(false /* loading */, true /* animate */); - } - - /** - * Creates a heading below decor_title and above the rest of the preferences. This heading - * displays the app name and banner icon. It's used in both system and additional permissions - * fragments for each app. The styling used is the same as a leanback preference with a - * customized background color - * @param context The context the preferences created on - * @return The preference header to be inserted as the first preference in the list. - */ - private Preference createHeaderLineTwoPreference(Context context) { - Preference headerLineTwo = new Preference(context) { - @Override - public void onBindViewHolder(PreferenceViewHolder holder) { - super.onBindViewHolder(holder); - holder.itemView.setBackgroundColor( - getResources().getColor(R.color.lb_header_banner_color)); - } - }; - headerLineTwo.setKey(HEADER_PREFERENCE_KEY); - headerLineTwo.setSelectable(false); - headerLineTwo.setTitle(mLabel); - headerLineTwo.setIcon(mIcon); - return headerLineTwo; - } - - @Override - public boolean onPreferenceChange(final Preference preference, Object newValue) { - String groupName = preference.getKey(); - final AppPermissionGroup group = mAppPermissions.getPermissionGroup(groupName); - - if (group == null) { - return false; - } - - addToggledGroup(group); - - if (LocationUtils.isLocationGroupAndProvider(group.getName(), group.getApp().packageName)) { - LocationUtils.showLocationDialog(getContext(), mAppPermissions.getAppLabel()); - return false; - } - if (newValue == Boolean.TRUE) { - group.grantRuntimePermissions(false); - } else { - final boolean grantedByDefault = group.hasGrantedByDefaultPermission(); - if (grantedByDefault || (!group.doesSupportRuntimePermissions() - && !mHasConfirmedRevoke)) { - new AlertDialog.Builder(getContext()) - .setMessage(grantedByDefault ? R.string.system_warning - : R.string.old_sdk_deny_warning) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.grant_dialog_button_deny_anyway, - (dialog, which) -> { - ((SwitchPreference) preference).setChecked(false); - group.revokeRuntimePermissions(false); - if (!grantedByDefault) { - mHasConfirmedRevoke = true; - } - }) - .show(); - return false; - } else { - group.revokeRuntimePermissions(false); - } - } - - return true; - } - - @Override - public void onPause() { - super.onPause(); - logToggledGroups(); - } - - private void addToggledGroup(AppPermissionGroup group) { - if (mToggledGroups == null) { - mToggledGroups = new ArraySet<>(); - } - mToggledGroups.add(group); - } - - private void logToggledGroups() { - if (mToggledGroups != null) { - SafetyNetLogger.logPermissionsToggled(mToggledGroups); - mToggledGroups = null; - } - } - - private void setPreferencesCheckedState() { - setPreferencesCheckedState(getPreferenceScreen()); - if (mExtraScreen != null) { - setPreferencesCheckedState(mExtraScreen); - } - } - - private void setPreferencesCheckedState(PreferenceScreen screen) { - int preferenceCount = screen.getPreferenceCount(); - for (int i = 0; i < preferenceCount; i++) { - Preference preference = screen.getPreference(i); - if (preference instanceof SwitchPreference) { - SwitchPreference switchPref = (SwitchPreference) preference; - AppPermissionGroup group = mAppPermissions.getPermissionGroup(switchPref.getKey()); - if (group != null) { - switchPref.setChecked(group.areRuntimePermissionsGranted()); - } - } - } - } - - private static PackageInfo getPackageInfo(Activity activity, String packageName) { - try { - return activity.getPackageManager().getPackageInfo( - packageName, PackageManager.GET_PERMISSIONS); - } catch (PackageManager.NameNotFoundException e) { - Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e); - return null; - } - } - - public static class AdditionalPermissionsFragment extends SettingsWithHeader { - AppPermissionsFragment mOuterFragment; - - @Override - public void onCreate(Bundle savedInstanceState) { - mOuterFragment = (AppPermissionsFragment) getTargetFragment(); - super.onCreate(savedInstanceState); - setHasOptionsMenu(true); - } - - @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - setPreferenceScreen(mOuterFragment.mExtraScreen); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME); - bindUi(this, getPackageInfo(getActivity(), packageName)); - } - - private static void bindUi(SettingsWithHeader fragment, PackageInfo packageInfo) { - Activity activity = fragment.getActivity(); - PackageManager pm = activity.getPackageManager(); - ApplicationInfo appInfo = packageInfo.applicationInfo; - Intent infoIntent = null; - if (!activity.getIntent().getBooleanExtra(EXTRA_HIDE_INFO_BUTTON, false)) { - infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) - .setData(Uri.fromParts("package", packageInfo.packageName, null)); - } - - Drawable icon = appInfo.loadIcon(pm); - CharSequence label = appInfo.loadLabel(pm); - fragment.setHeader(icon, label, infoIntent, fragment.getString( - R.string.additional_permissions_decor_title)); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - getFragmentManager().popBackStack(); - return true; - } - return super.onOptionsItemSelected(item); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/GrantPermissionsViewHandlerImpl.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/GrantPermissionsViewHandlerImpl.java deleted file mode 100644 index c71835734f5e8b8f1ed79043de444dc677c0ba0b..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/GrantPermissionsViewHandlerImpl.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.android.packageinstaller.permission.ui.television; - -import android.content.Context; -import android.graphics.PixelFormat; -import android.graphics.drawable.Icon; -import android.os.Bundle; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.WindowManager; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler; - -/** - * TV-specific view handler for the grant permissions activity. - */ -public final class GrantPermissionsViewHandlerImpl implements GrantPermissionsViewHandler, OnClickListener { - - private static final String ARG_GROUP_NAME = "ARG_GROUP_NAME"; - - private final Context mContext; - - private ResultListener mResultListener; - - private String mGroupName; - - private LinearLayout mRootView; - private TextView mMessageView; - private ImageView mIconView; - private TextView mCurrentGroupView; - private Button mAllowButton; - private Button mSoftDenyButton; - private Button mHardDenyButton; - - public GrantPermissionsViewHandlerImpl(Context context, String appPackageName) { - mContext = context; - } - - @Override - public GrantPermissionsViewHandlerImpl setResultListener(ResultListener listener) { - mResultListener = listener; - return this; - } - - @Override - public View createView() { - mRootView = (LinearLayout) LayoutInflater.from(mContext) - .inflate(R.layout.grant_permissions, null); - - mMessageView = (TextView) mRootView.findViewById(R.id.permission_message); - mIconView = (ImageView) mRootView.findViewById(R.id.permission_icon); - mCurrentGroupView = (TextView) mRootView.findViewById(R.id.current_page_text); - mAllowButton = (Button) mRootView.findViewById(R.id.permission_allow_button); - mSoftDenyButton = (Button) mRootView.findViewById(R.id.permission_deny_button); - mHardDenyButton = (Button) mRootView.findViewById( - R.id.permission_deny_dont_ask_again_button); - - mAllowButton.setOnClickListener(this); - mSoftDenyButton.setOnClickListener(this); - mHardDenyButton.setOnClickListener(this); - - return mRootView; - } - - @Override - public void updateWindowAttributes(WindowManager.LayoutParams outLayoutParams) { - outLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; - outLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; - outLayoutParams.format = PixelFormat.OPAQUE; - outLayoutParams.gravity = Gravity.BOTTOM; - outLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; - outLayoutParams.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; - } - - @Override - public void updateUi(String groupName, int groupCount, int groupIndex, Icon icon, - CharSequence message, CharSequence detailMessage, boolean showForegroundChooser, - boolean showDoNotAsk) { - // TODO: Handle detailMessage - // TODO: Handle showForegroundChooser - - mGroupName = groupName; - - mMessageView.setText(message); - - if (icon != null) { - mIconView.setImageIcon(icon); - } - - mHardDenyButton.setVisibility(showDoNotAsk ? View.VISIBLE : View.GONE); - if (groupCount > 1) { - mCurrentGroupView.setVisibility(View.VISIBLE); - mCurrentGroupView.setText(mContext.getString(R.string.current_permission_template, - groupIndex + 1, groupCount)); - } else { - mCurrentGroupView.setVisibility(View.INVISIBLE); - } - } - - @Override - public void saveInstanceState(Bundle outState) { - outState.putString(ARG_GROUP_NAME, mGroupName); - } - - @Override - public void loadInstanceState(Bundle savedInstanceState) { - mGroupName = savedInstanceState.getString(ARG_GROUP_NAME); - } - - @Override - public void onClick(View view) { - switch (view.getId()) { - case R.id.permission_allow_button: - mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ALWAYS); - break; - case R.id.permission_deny_button: - mResultListener.onPermissionGrantResult(mGroupName, DENIED); - break; - case R.id.permission_deny_dont_ask_again_button: - mResultListener.onPermissionGrantResult(mGroupName, DENIED_DO_NOT_ASK_AGAIN); - break; - } - } - - @Override - public void onBackPressed() { - if (mResultListener != null) { - mResultListener.onPermissionGrantResult(mGroupName, DENIED); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/ManagePermissionsFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/ManagePermissionsFragment.java deleted file mode 100644 index 19f01d0f91c6944f1a291ada9af7650fa51162d6..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/ManagePermissionsFragment.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.packageinstaller.permission.ui.television; - -import android.app.ActionBar; -import android.app.FragmentTransaction; -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import androidx.annotation.Nullable; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceClickListener; -import androidx.preference.PreferenceScreen; -import android.util.ArraySet; -import android.util.Log; -import android.view.MenuItem; -import android.view.View; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.PermissionApps.PmCache; -import com.android.packageinstaller.permission.model.PermissionGroup; -import com.android.packageinstaller.permission.model.PermissionGroups; -import com.android.packageinstaller.permission.utils.Utils; - -import java.util.List; - -public final class ManagePermissionsFragment extends SettingsWithHeader - implements PermissionGroups.PermissionsGroupsChangeCallback, OnPreferenceClickListener { - private static final String LOG_TAG = "ManagePermissionsFragment"; - - private static final String OS_PKG = "android"; - - private static final String EXTRA_PREFS_KEY = "extra_prefs_key"; - - private ArraySet<String> mLauncherPkgs; - - private PermissionGroups mPermissions; - - private PreferenceScreen mExtraScreen; - - public static ManagePermissionsFragment newInstance() { - return new ManagePermissionsFragment(); - } - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - setLoading(true /* loading */, false /* animate */); - setHasOptionsMenu(true); - final ActionBar ab = getActivity().getActionBar(); - if (ab != null) { - ab.setDisplayHomeAsUpEnabled(true); - } - mLauncherPkgs = Utils.getLauncherPackages(getContext()); - mPermissions = new PermissionGroups(getContext(), getLoaderManager(), this); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - getActivity().finish(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public boolean onPreferenceClick(Preference preference) { - String key = preference.getKey(); - - PermissionGroup group = mPermissions.getGroup(key); - if (group == null) { - return false; - } - - Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSION_APPS) - .putExtra(Intent.EXTRA_PERMISSION_NAME, key); - try { - getActivity().startActivity(intent); - } catch (ActivityNotFoundException e) { - Log.w(LOG_TAG, "No app to handle " + intent); - } - - return true; - } - - @Override - public void onPermissionGroupsChanged() { - updatePermissionsUi(); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - bindPermissionUi(this, getView()); - } - - private static void bindPermissionUi(SettingsWithHeader fragment, @Nullable View rootView) { - if (fragment == null || rootView == null) { - return; - } - fragment.setHeader(null, null, null, fragment.getString( - R.string.manage_permissions_decor_title)); - } - - private void updatePermissionsUi() { - Context context = getPreferenceManager().getContext(); - if (context == null) { - return; - } - - List<PermissionGroup> groups = mPermissions.getGroups(); - PreferenceScreen screen = getPreferenceScreen(); - - // Use this to speed up getting the info for all of the PermissionApps below. - // Create a new one for each refresh to make sure it has fresh data. - PmCache cache = new PmCache(getContext().getPackageManager()); - for (PermissionGroup group : groups) { - boolean isSystemPermission = group.getDeclaringPackage().equals(OS_PKG); - - Preference preference = findPreference(group.getName()); - if (preference == null && mExtraScreen != null) { - preference = mExtraScreen.findPreference(group.getName()); - } - if (preference == null) { - preference = new Preference(context); - preference.setOnPreferenceClickListener(this); - preference.setKey(group.getName()); - preference.setIcon(Utils.applyTint(context, group.getIcon(), - android.R.attr.colorControlNormal)); - preference.setTitle(group.getLabel()); - // Set blank summary so that no resizing/jumping happens when the summary is loaded. - preference.setSummary(" "); - preference.setPersistent(false); - if (isSystemPermission) { - screen.addPreference(preference); - } else { - if (mExtraScreen == null) { - mExtraScreen = getPreferenceManager().createPreferenceScreen(context); - } - mExtraScreen.addPreference(preference); - } - } - - preference.setSummary(getString(R.string.app_permissions_group_summary, - group.getGranted(), group.getTotal())); - } - - if (mExtraScreen != null && mExtraScreen.getPreferenceCount() > 0 - && screen.findPreference(EXTRA_PREFS_KEY) == null) { - Preference extraScreenPreference = new Preference(context); - extraScreenPreference.setKey(EXTRA_PREFS_KEY); - extraScreenPreference.setIcon(Utils.applyTint(context, - R.drawable.ic_more_items, - android.R.attr.colorControlNormal)); - extraScreenPreference.setTitle(R.string.additional_permissions); - extraScreenPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - AdditionalPermissionsFragment frag = new AdditionalPermissionsFragment(); - frag.setTargetFragment(ManagePermissionsFragment.this, 0); - FragmentTransaction ft = getFragmentManager().beginTransaction(); - ft.replace(android.R.id.content, frag); - ft.addToBackStack(null); - ft.commit(); - return true; - } - }); - int count = mExtraScreen.getPreferenceCount(); - extraScreenPreference.setSummary(getResources().getQuantityString( - R.plurals.additional_permissions_more, count, count)); - screen.addPreference(extraScreenPreference); - } - if (screen.getPreferenceCount() != 0) { - setLoading(false /* loading */, true /* animate */); - } - } - - public static class AdditionalPermissionsFragment extends SettingsWithHeader { - @Override - public void onCreate(Bundle icicle) { - setLoading(true /* loading */, false /* animate */); - super.onCreate(icicle); - getActivity().setTitle(R.string.additional_permissions); - setHasOptionsMenu(true); - } - - @Override - public void onDestroy() { - getActivity().setTitle(R.string.app_permissions); - super.onDestroy(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - getFragmentManager().popBackStack(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - bindPermissionUi(this, getView()); - } - - private static void bindPermissionUi(SettingsWithHeader fragment, @Nullable View rootView) { - if (fragment == null || rootView == null) { - return; - } - fragment.setHeader(null, null, null, - fragment.getString(R.string.additional_permissions_decor_title)); - } - - @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - setPreferenceScreen(((ManagePermissionsFragment) getTargetFragment()).mExtraScreen); - setLoading(false /* loading */, true /* animate */); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java deleted file mode 100644 index 6a0a9e7c72752d7871e815a1f2ca16b14a3fc65b..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.packageinstaller.permission.ui.television; - -import android.app.ActionBar; -import android.app.AlertDialog; -import android.app.Fragment; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.util.ArraySet; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.TextView; - -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.Preference.OnPreferenceClickListener; -import androidx.preference.PreferenceScreen; -import androidx.preference.SwitchPreference; - -import com.android.packageinstaller.DeviceUtils; -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.PermissionApps; -import com.android.packageinstaller.permission.model.PermissionApps.Callback; -import com.android.packageinstaller.permission.model.PermissionApps.PermissionApp; -import com.android.packageinstaller.permission.ui.ReviewPermissionsActivity; -import com.android.packageinstaller.permission.utils.LocationUtils; -import com.android.packageinstaller.permission.utils.SafetyNetLogger; -import com.android.packageinstaller.permission.utils.Utils; - -public final class PermissionAppsFragment extends SettingsWithHeader implements Callback, - OnPreferenceChangeListener { - - private static final int MENU_SHOW_SYSTEM = Menu.FIRST; - private static final int MENU_HIDE_SYSTEM = Menu.FIRST + 1; - private static final String KEY_SHOW_SYSTEM_PREFS = "_showSystem"; - - public static PermissionAppsFragment newInstance(String permissionName) { - return setPermissionName(new PermissionAppsFragment(), permissionName); - } - - private static <T extends Fragment> T setPermissionName(T fragment, String permissionName) { - Bundle arguments = new Bundle(); - arguments.putString(Intent.EXTRA_PERMISSION_NAME, permissionName); - fragment.setArguments(arguments); - return fragment; - } - - private PermissionApps mPermissionApps; - - private PreferenceScreen mExtraScreen; - - private ArraySet<AppPermissionGroup> mToggledGroups; - private ArraySet<String> mLauncherPkgs; - private boolean mHasConfirmedRevoke; - - private boolean mShowSystem; - private boolean mHasSystemApps; - private MenuItem mShowSystemMenu; - private MenuItem mHideSystemMenu; - - private Callback mOnPermissionsLoadedListener; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setLoading(true /* loading */, false /* animate */); - mLauncherPkgs = Utils.getLauncherPackages(getContext()); - String groupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME); - mPermissionApps = new PermissionApps(getActivity(), groupName, this); - } - - @Override - public void onStart() { - super.onStart(); - - setHasOptionsMenu(true); - final ActionBar ab = getActivity().getActionBar(); - if (ab != null) { - ab.setDisplayHomeAsUpEnabled(true); - } - - mPermissionApps.refresh(true); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - 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 - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - getActivity().finish(); - return true; - case MENU_SHOW_SYSTEM: - case MENU_HIDE_SYSTEM: - mShowSystem = item.getItemId() == MENU_SHOW_SYSTEM; - if (mPermissionApps.getApps() != null) { - onPermissionsLoaded(mPermissionApps); - } - updateMenu(); - break; - } - return super.onOptionsItemSelected(item); - } - - private void updateMenu() { - mShowSystemMenu.setVisible(!mShowSystem); - mHideSystemMenu.setVisible(mShowSystem); - } - - @Override - protected void onSetEmptyText(TextView textView) { - textView.setText(R.string.no_apps); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - bindUi(this, mPermissionApps); - } - - private static void bindUi(SettingsWithHeader fragment, PermissionApps permissionApps) { - final Drawable icon = permissionApps.getIcon(); - final CharSequence label = permissionApps.getLabel(); - - fragment.setHeader(null, null, null, - fragment.getString(R.string.permission_apps_decor_title, label)); - } - - private void setOnPermissionsLoadedListener(Callback callback) { - mOnPermissionsLoadedListener = callback; - } - - @Override - public void onPermissionsLoaded(PermissionApps permissionApps) { - Context context = getPreferenceManager().getContext(); - - if (context == null) { - return; - } - - boolean isTelevision = DeviceUtils.isTelevision(context); - PreferenceScreen screen = getPreferenceScreen(); - - ArraySet<String> preferencesToRemove = new ArraySet<>(); - for (int i = 0, n = screen.getPreferenceCount(); i < n; i++) { - preferencesToRemove.add(screen.getPreference(i).getKey()); - } - if (mExtraScreen != null) { - for (int i = 0, n = mExtraScreen.getPreferenceCount(); i < n; i++) { - preferencesToRemove.add(mExtraScreen.getPreference(i).getKey()); - } - } - - mHasSystemApps = false; - boolean menuOptionsInvalided = false; - - for (PermissionApp app : permissionApps.getApps()) { - if (!Utils.shouldShowPermission(app.getPermissionGroup())) { - continue; - } - - String key = app.getKey(); - preferencesToRemove.remove(key); - Preference existingPref = screen.findPreference(key); - if (existingPref == null && mExtraScreen != null) { - existingPref = mExtraScreen.findPreference(key); - } - - boolean isSystemApp = Utils.isSystem(app, mLauncherPkgs); - - if (isSystemApp && !menuOptionsInvalided) { - mHasSystemApps = true; - getActivity().invalidateOptionsMenu(); - menuOptionsInvalided = true; - } - - if (isSystemApp && !isTelevision && !mShowSystem) { - if (existingPref != null) { - screen.removePreference(existingPref); - } - continue; - } - - if (existingPref != null) { - // If existing preference - only update its state. - if (app.isPolicyFixed()) { - existingPref.setSummary(getString( - R.string.permission_summary_enforced_by_policy)); - } - existingPref.setPersistent(false); - existingPref.setEnabled(!app.isPolicyFixed()); - if (existingPref instanceof SwitchPreference) { - ((SwitchPreference) existingPref) - .setChecked(app.areRuntimePermissionsGranted()); - } - continue; - } - - SwitchPreference pref = new SwitchPreference(context); - pref.setOnPreferenceChangeListener(this); - pref.setKey(app.getKey()); - pref.setIcon(app.getIcon()); - pref.setTitle(app.getLabel()); - if (app.isPolicyFixed()) { - pref.setSummary(getString(R.string.permission_summary_enforced_by_policy)); - } - pref.setPersistent(false); - pref.setEnabled(!app.isPolicyFixed()); - pref.setChecked(app.areRuntimePermissionsGranted()); - - if (isSystemApp && isTelevision) { - if (mExtraScreen == null) { - mExtraScreen = getPreferenceManager().createPreferenceScreen(context); - } - mExtraScreen.addPreference(pref); - } else { - screen.addPreference(pref); - } - } - - if (mExtraScreen != null) { - preferencesToRemove.remove(KEY_SHOW_SYSTEM_PREFS); - Preference pref = screen.findPreference(KEY_SHOW_SYSTEM_PREFS); - - if (pref == null) { - pref = new Preference(context); - pref.setKey(KEY_SHOW_SYSTEM_PREFS); - pref.setIcon(Utils.applyTint(context, R.drawable.ic_toc, - android.R.attr.colorControlNormal)); - pref.setTitle(R.string.preference_show_system_apps); - pref.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - SystemAppsFragment frag = new SystemAppsFragment(); - setPermissionName(frag, getArguments().getString( - Intent.EXTRA_PERMISSION_NAME)); - frag.setTargetFragment(PermissionAppsFragment.this, 0); - getFragmentManager().beginTransaction() - .replace(android.R.id.content, frag) - .addToBackStack("SystemApps") - .commit(); - return true; - } - }); - screen.addPreference(pref); - } - - int grantedCount = 0; - for (int i = 0, n = mExtraScreen.getPreferenceCount(); i < n; i++) { - if (((SwitchPreference) mExtraScreen.getPreference(i)).isChecked()) { - grantedCount++; - } - } - pref.setSummary(getString(R.string.app_permissions_group_summary, - grantedCount, mExtraScreen.getPreferenceCount())); - } - - for (String key : preferencesToRemove) { - Preference pref = screen.findPreference(key); - if (pref != null) { - screen.removePreference(pref); - } else if (mExtraScreen != null) { - pref = mExtraScreen.findPreference(key); - if (pref != null) { - mExtraScreen.removePreference(pref); - } - } - } - - setLoading(false /* loading */, true /* animate */); - - if (mOnPermissionsLoadedListener != null) { - mOnPermissionsLoadedListener.onPermissionsLoaded(permissionApps); - } - } - - @Override - public boolean onPreferenceChange(final Preference preference, Object newValue) { - String pkg = preference.getKey(); - final PermissionApp app = mPermissionApps.getApp(pkg); - - if (app == null) { - return false; - } - - if (LocationUtils.isLocationGroupAndProvider(mPermissionApps.getGroupName(), - app.getPackageName())) { - LocationUtils.showLocationDialog(getContext(), app.getLabel()); - return false; - } - - addToggledGroup(app.getPackageName(), app.getPermissionGroup()); - - if (app.isReviewRequired()) { - Intent intent = new Intent(getActivity(), ReviewPermissionsActivity.class); - intent.putExtra(Intent.EXTRA_PACKAGE_NAME, app.getPackageName()); - startActivity(intent); - return false; - } - - if (newValue == Boolean.TRUE) { - app.grantRuntimePermissions(); - } else { - final boolean grantedByDefault = app.hasGrantedByDefaultPermissions(); - if (grantedByDefault || (!app.doesSupportRuntimePermissions() - && !mHasConfirmedRevoke)) { - new AlertDialog.Builder(getContext()) - .setMessage(grantedByDefault ? R.string.system_warning - : R.string.old_sdk_deny_warning) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.grant_dialog_button_deny_anyway, - new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - ((SwitchPreference) preference).setChecked(false); - app.revokeRuntimePermissions(); - if (!grantedByDefault) { - mHasConfirmedRevoke = true; - } - } - }) - .show(); - return false; - } else { - app.revokeRuntimePermissions(); - } - } - return true; - } - - @Override - public void onStop() { - super.onStop(); - logToggledGroups(); - } - - private void addToggledGroup(String packageName, AppPermissionGroup group) { - if (mToggledGroups == null) { - mToggledGroups = new ArraySet<>(); - } - - mToggledGroups.add(group); - } - - private void logToggledGroups() { - if (mToggledGroups != null) { - SafetyNetLogger.logPermissionsToggled(mToggledGroups); - mToggledGroups = null; - } - } - - public static class SystemAppsFragment extends SettingsWithHeader implements Callback { - PermissionAppsFragment mOuterFragment; - - @Override - public void onCreate(Bundle savedInstanceState) { - mOuterFragment = (PermissionAppsFragment) getTargetFragment(); - setLoading(true /* loading */, false /* animate */); - super.onCreate(savedInstanceState); - } - - @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - if (mOuterFragment.mExtraScreen != null) { - setPreferenceScreen(); - } else { - mOuterFragment.setOnPermissionsLoadedListener(this); - } - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - String groupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME); - PermissionApps permissionApps = new PermissionApps(getActivity(), groupName, null); - bindUi(this, permissionApps); - } - - @Override - public void onResume() { - super.onResume(); - mOuterFragment.mPermissionApps.refresh(true); - } - - @Override - public void onDestroy() { - super.onDestroy(); - mOuterFragment.setOnPermissionsLoadedListener(null); - } - - - private static void bindUi(SettingsWithHeader fragment, PermissionApps permissionApps) { - final CharSequence label = permissionApps.getLabel(); - fragment.setHeader(null, null, null, - fragment.getString(R.string.system_apps_decor_title, label)); - } - - @Override - public void onPermissionsLoaded(PermissionApps permissionApps) { - setPreferenceScreen(); - } - - private void setPreferenceScreen() { - setPreferenceScreen(mOuterFragment.mExtraScreen); - setLoading(false /* loading */, true /* animate */); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/PermissionsFrameFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/PermissionsFrameFragment.java deleted file mode 100644 index af4593ae0f649dd2f3593e20f4a9184fa63808f8..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/PermissionsFrameFragment.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui.television; - -import android.os.Bundle; -import androidx.annotation.Nullable; -import androidx.preference.PreferenceFragment; -import androidx.leanback.widget.VerticalGridView; -import androidx.preference.PreferenceScreen; -import androidx.recyclerview.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.Animation; -import android.view.animation.Animation.AnimationListener; -import android.view.animation.AnimationUtils; -import android.widget.TextView; - -import com.android.packageinstaller.R; - -public abstract class PermissionsFrameFragment extends PreferenceFragment { - - // Key identifying the preference used on TV as the extra header in a permission fragment. - // This is to distinguish it from the rest of the preferences - protected static final String HEADER_PREFERENCE_KEY = "HeaderPreferenceKey"; - - private ViewGroup mPreferencesContainer; - - // TV-specific instance variable - @Nullable private RecyclerView mGridView; - - private View mLoadingView; - private ViewGroup mPrefsView; - private boolean mIsLoading; - - /** - * Returns the view group that holds the preferences objects. This will - * only be set after {@link #onCreateView} has been called. - */ - protected final ViewGroup getPreferencesContainer() { - return mPreferencesContainer; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.permissions_frame, container, - false); - mPrefsView = (ViewGroup) rootView.findViewById(R.id.prefs_container); - if (mPrefsView == null) { - mPrefsView = rootView; - } - mLoadingView = rootView.findViewById(R.id.loading_container); - mPreferencesContainer = (ViewGroup) super.onCreateView( - inflater, mPrefsView, savedInstanceState); - setLoading(mIsLoading, false, true /* force */); - mPrefsView.addView(mPreferencesContainer); - return rootView; - } - - @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - PreferenceScreen preferences = getPreferenceScreen(); - if (preferences == null) { - preferences = getPreferenceManager().createPreferenceScreen(getActivity()); - setPreferenceScreen(preferences); - } - } - - protected void setLoading(boolean loading, boolean animate) { - setLoading(loading, animate, false); - } - - private void setLoading(boolean loading, boolean animate, boolean force) { - if (mIsLoading != loading || force) { - mIsLoading = loading; - if (getView() == null) { - // If there is no created view, there is no reason to animate. - animate = false; - } - if (mPrefsView != null) { - setViewShown(mPrefsView, !loading, animate); - } - if (mLoadingView != null) { - setViewShown(mLoadingView, loading, animate); - } - } - } - - private void setViewShown(final View view, boolean shown, boolean animate) { - if (animate) { - Animation animation = AnimationUtils.loadAnimation(getContext(), - shown ? android.R.anim.fade_in : android.R.anim.fade_out); - if (shown) { - view.setVisibility(View.VISIBLE); - } else { - animation.setAnimationListener(new AnimationListener() { - @Override - public void onAnimationStart(Animation animation) { - } - - @Override - public void onAnimationRepeat(Animation animation) { - } - - @Override - public void onAnimationEnd(Animation animation) { - view.setVisibility(View.INVISIBLE); - } - }); - } - view.startAnimation(animation); - } else { - view.clearAnimation(); - view.setVisibility(shown ? View.VISIBLE : View.INVISIBLE); - } - } - - @Override - public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, - Bundle savedInstanceState) { - VerticalGridView verticalGridView = (VerticalGridView) inflater.inflate( - R.layout.leanback_preferences_list, parent, false); - verticalGridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE); - verticalGridView.setFocusScrollStrategy(VerticalGridView.FOCUS_SCROLL_ALIGNED); - mGridView = verticalGridView; - return mGridView; - } - - @Override - protected RecyclerView.Adapter<?> onCreateAdapter(PreferenceScreen preferenceScreen) { - final RecyclerView.Adapter<?> adapter = super.onCreateAdapter(preferenceScreen); - - if (adapter != null) { - final TextView emptyView = (TextView) getView().findViewById(R.id.no_permissions); - onSetEmptyText(emptyView); - final RecyclerView recyclerView = getListView(); - adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { - @Override - public void onChanged() { - checkEmpty(); - } - - @Override - public void onItemRangeInserted(int positionStart, int itemCount) { - checkEmpty(); - } - - @Override - public void onItemRangeRemoved(int positionStart, int itemCount) { - checkEmpty(); - } - - private void checkEmpty() { - boolean isEmpty = isPreferenceListEmpty(); - emptyView.setVisibility(isEmpty ? View.VISIBLE : View.GONE); - recyclerView.setVisibility(isEmpty && adapter.getItemCount() == 0 ? - View.GONE : View.VISIBLE); - if (!isEmpty && mGridView != null) { - mGridView.requestFocus(); - } - } - }); - - boolean isEmpty = isPreferenceListEmpty(); - emptyView.setVisibility(isEmpty ? View.VISIBLE : View.GONE); - recyclerView.setVisibility(isEmpty && adapter.getItemCount() == 0 ? - View.GONE : View.VISIBLE); - if (!isEmpty && mGridView != null) { - mGridView.requestFocus(); - } - } - - return adapter; - } - - private boolean isPreferenceListEmpty() { - PreferenceScreen screen = getPreferenceScreen(); - return screen.getPreferenceCount() == 0 || ( - screen.getPreferenceCount() == 1 && - (screen.findPreference(HEADER_PREFERENCE_KEY) != null)); - } - - /** - * Hook for subclasses to change the default text of the empty view. - * Base implementation leaves the default empty view text. - * - * @param textView the empty text view - */ - protected void onSetEmptyText(TextView textView) { - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/SettingsWithHeader.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/SettingsWithHeader.java deleted file mode 100644 index 06f7c1426af56801c24d2118dcd1e8fe0c5f60de..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/television/SettingsWithHeader.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui.television; - -import android.content.Intent; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; -import com.android.packageinstaller.DeviceUtils; -import com.android.packageinstaller.R; - -public abstract class SettingsWithHeader extends PermissionsFrameFragment - implements OnClickListener { - - private View mHeader; - protected Intent mInfoIntent; - protected Drawable mIcon; - protected CharSequence mLabel; - protected CharSequence mDecorTitle; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - ViewGroup root = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState); - - mHeader = inflater.inflate(R.layout.header, root, false); - getPreferencesContainer().addView(mHeader, 0); - updateHeader(); - - return root; - } - - public void setHeader(Drawable icon, CharSequence label, Intent infoIntent, - CharSequence decorTitle) { - mIcon = icon; - mLabel = label; - mInfoIntent = infoIntent; - mDecorTitle = decorTitle; - updateHeader(); - } - - public View getHeader() { - return mHeader; - } - - protected void updateHeader() { - final TextView decorTitle = (TextView) mHeader.findViewById(R.id.decor_title); - decorTitle.setText(mDecorTitle); - } - - @Override - public void onClick(View v) { - getActivity().startActivity(mInfoIntent); - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/wear/AppPermissionsFragmentWear.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/wear/AppPermissionsFragmentWear.java deleted file mode 100644 index 20495aac245133a4c2111d20c375fd7ff15c48b4..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/wear/AppPermissionsFragmentWear.java +++ /dev/null @@ -1,403 +0,0 @@ -/* -* Copyright (C) 2015 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package com.android.packageinstaller.permission.ui.wear; - -import android.app.Activity; -import android.app.Fragment; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PermissionInfo; -import android.os.Build; -import android.os.Bundle; -import android.os.UserHandle; -import android.preference.Preference; -import android.preference.PreferenceFragment; -import android.preference.PreferenceScreen; -import android.preference.SwitchPreference; -import android.util.ArraySet; -import android.util.Log; -import android.widget.Toast; - -import androidx.wear.ble.view.WearableDialogHelper; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.AppPermissions; -import com.android.packageinstaller.permission.model.Permission; -import com.android.packageinstaller.permission.utils.ArrayUtils; -import com.android.packageinstaller.permission.utils.LocationUtils; -import com.android.packageinstaller.permission.utils.SafetyNetLogger; -import com.android.packageinstaller.permission.utils.Utils; -import com.android.settingslib.RestrictedLockUtils; -import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; - -import java.util.ArrayList; -import java.util.List; - -public final class AppPermissionsFragmentWear extends PreferenceFragment { - private static final String LOG_TAG = "AppPermFragWear"; - - private static final String KEY_NO_PERMISSIONS = "no_permissions"; - - public static AppPermissionsFragmentWear newInstance(String packageName) { - return setPackageName(new AppPermissionsFragmentWear(), packageName); - } - - private static <T extends Fragment> T setPackageName(T fragment, String packageName) { - Bundle arguments = new Bundle(); - arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName); - fragment.setArguments(arguments); - return fragment; - } - - private PackageManager mPackageManager; - private ArraySet<AppPermissionGroup> mToggledGroups; - private AppPermissions mAppPermissions; - - private boolean mHasConfirmedRevoke; - - /** - * Provides click behavior for disabled preferences. - * We can't use {@link PreferenceFragment#onPreferenceTreeClick}, as the base - * {@link SwitchPreference} doesn't delegate to that method if the preference is disabled. - */ - private static class PermissionSwitchPreference extends SwitchPreference { - - private final Activity mActivity; - - public PermissionSwitchPreference(Activity activity) { - super(activity); - this.mActivity = activity; - } - - @Override - public void performClick(PreferenceScreen preferenceScreen) { - super.performClick(preferenceScreen); - if (!isEnabled()) { - // If setting the permission is disabled, it must have been locked - // by the device or profile owner. So get that info and pass it to - // the support details dialog. - EnforcedAdmin deviceOrProfileOwner = RestrictedLockUtils.getProfileOrDeviceOwner( - mActivity, UserHandle.myUserId()); - RestrictedLockUtils.sendShowAdminSupportDetailsIntent( - mActivity, deviceOrProfileOwner); - } - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME); - Activity activity = getActivity(); - mPackageManager = activity.getPackageManager(); - - PackageInfo packageInfo; - - try { - packageInfo = mPackageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); - } catch (PackageManager.NameNotFoundException e) { - Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e); - packageInfo = null; - } - - if (packageInfo == null) { - Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show(); - activity.finish(); - return; - } - - mAppPermissions = new AppPermissions( - activity, packageInfo, true, () -> getActivity().finish()); - - addPreferencesFromResource(R.xml.watch_permissions); - initializePermissionGroupList(); - } - - @Override - public void onResume() { - super.onResume(); - mAppPermissions.refresh(); - - // Also refresh the UI - for (final AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { - if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName())) { - for (PermissionInfo perm : getPermissionInfosFromGroup(group)) { - setPreferenceCheckedIfPresent(perm.name, - group.areRuntimePermissionsGranted(new String[]{ perm.name })); - } - } else { - setPreferenceCheckedIfPresent(group.getName(), group.areRuntimePermissionsGranted()); - } - } - } - - @Override - public void onPause() { - super.onPause(); - logAndClearToggledGroups(); - } - - private void initializePermissionGroupList() { - List<AppPermissionGroup> groups = mAppPermissions.getPermissionGroups(); - List<SwitchPreference> nonSystemPreferences = new ArrayList<>(); - - if (!groups.isEmpty()) { - getPreferenceScreen().removePreference(findPreference(KEY_NO_PERMISSIONS)); - } - - for (final AppPermissionGroup group : groups) { - if (!Utils.shouldShowPermission(group)) { - continue; - } - - boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG); - - if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName())) { - // If permission is controlled individually, we show all requested permission - // inside this group. - for (PermissionInfo perm : getPermissionInfosFromGroup(group)) { - final SwitchPreference pref = createSwitchPreferenceForPermission(group, perm); - showOrAddToNonSystemPreferences(pref, nonSystemPreferences, isPlatform); - } - } else { - final SwitchPreference pref = createSwitchPreferenceForGroup(group); - showOrAddToNonSystemPreferences(pref, nonSystemPreferences, isPlatform); - } - } - - // Now add the non-system settings to the end of the list - for (SwitchPreference nonSystemPreference : nonSystemPreferences) { - getPreferenceScreen().addPreference(nonSystemPreference); - } - } - - private void showOrAddToNonSystemPreferences(SwitchPreference pref, - List<SwitchPreference> nonSystemPreferences, // Mutate - boolean isPlatform) { - // The UI shows System settings first, then non-system settings - if (isPlatform) { - getPreferenceScreen().addPreference(pref); - } else { - nonSystemPreferences.add(pref); - } - } - - private SwitchPreference createSwitchPreferenceForPermission(AppPermissionGroup group, - PermissionInfo perm) { - final SwitchPreference pref = new PermissionSwitchPreference(getActivity()); - pref.setKey(perm.name); - pref.setTitle(perm.loadLabel(mPackageManager)); - pref.setChecked(group.areRuntimePermissionsGranted(new String[]{ perm.name })); - pref.setOnPreferenceChangeListener((p, newVal) -> { - if((Boolean) newVal) { - group.grantRuntimePermissions(false, new String[]{ perm.name }); - - if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName()) - && group.doesSupportRuntimePermissions()) { - // We are granting a permission from a group but since this is an - // individual permission control other permissions in the group may - // be revoked, hence we need to mark them user fixed to prevent the - // app from requesting a non-granted permission and it being granted - // because another permission in the group is granted. This applies - // only to apps that support runtime permissions. - String[] revokedPermissionsToFix = null; - final int permissionCount = group.getPermissions().size(); - - for (int i = 0; i < permissionCount; i++) { - Permission current = group.getPermissions().get(i); - if (!current.isGranted() && !current.isUserFixed()) { - revokedPermissionsToFix = ArrayUtils.appendString( - revokedPermissionsToFix, current.getName()); - } - } - - if (revokedPermissionsToFix != null) { - // If some permissions were not granted then they should be fixed. - group.revokeRuntimePermissions(true, revokedPermissionsToFix); - } - } - } else { - final Permission appPerm = getPermissionFromGroup(group, perm.name); - if (appPerm == null) { - return false; - } - - final boolean grantedByDefault = appPerm.isGrantedByDefault(); - if (grantedByDefault - || (!group.doesSupportRuntimePermissions() && !mHasConfirmedRevoke)) { - showRevocationWarningDialog( - (dialog, which) -> { - revokePermissionInGroup(group, perm.name); - pref.setChecked(false); - if (!appPerm.isGrantedByDefault()) { - mHasConfirmedRevoke = true; - } - }, - grantedByDefault - ? R.string.system_warning - : R.string.old_sdk_deny_warning); - return false; - } else { - revokePermissionInGroup(group, perm.name); - } - } - - return true; - }); - return pref; - } - - private void showRevocationWarningDialog( - DialogInterface.OnClickListener confirmListener, - int warningMessageId) { - new WearableDialogHelper.DialogBuilder(getContext()) - .setNegativeIcon(R.drawable.confirm_button) - .setPositiveIcon(R.drawable.cancel_button) - .setNegativeButton(R.string.grant_dialog_button_deny_anyway, confirmListener) - .setPositiveButton(R.string.cancel, null) - .setMessage(warningMessageId) - .show(); - } - - private static Permission getPermissionFromGroup(AppPermissionGroup group, String permName) { - final int permissionCount = group.getPermissions().size(); - - for (int i = 0; i < permissionCount; i++) { - Permission currentPerm = group.getPermissions().get(i); - if(currentPerm.getName().equals(permName)) { - return currentPerm; - }; - } - - if ("user".equals(Build.TYPE)) { - Log.e(LOG_TAG, String.format("The impossible happens, permission %s is not in group %s.", - permName, group.getName())); - return null; - } else { - // This is impossible, throw a fatal error in non-user build. - throw new IllegalArgumentException( - String.format("Permission %s is not in group %s", permName, group.getName())); - } - } - - private void revokePermissionInGroup(AppPermissionGroup group, String permName) { - group.revokeRuntimePermissions(true, new String[]{ permName }); - - if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName()) - && group.doesSupportRuntimePermissions() - && !group.areRuntimePermissionsGranted()) { - // If we just revoked the last permission we need to clear - // the user fixed state as now the app should be able to - // request them at runtime if supported. - group.revokeRuntimePermissions(false); - } - } - - private SwitchPreference createSwitchPreferenceForGroup(AppPermissionGroup group) { - final SwitchPreference pref = new PermissionSwitchPreference(getActivity()); - - pref.setKey(group.getName()); - pref.setTitle(group.getLabel()); - pref.setChecked(group.areRuntimePermissionsGranted()); - - if (group.isPolicyFixed()) { - pref.setEnabled(false); - } else { - pref.setOnPreferenceChangeListener((p, newVal) -> { - if (LocationUtils.isLocationGroupAndProvider( - group.getName(), group.getApp().packageName)) { - LocationUtils.showLocationDialog( - getContext(), mAppPermissions.getAppLabel()); - return false; - } - - if ((Boolean) newVal) { - setPermission(group, pref, true); - } else { - final boolean grantedByDefault = group.hasGrantedByDefaultPermission(); - if (grantedByDefault - || (!group.doesSupportRuntimePermissions() && !mHasConfirmedRevoke)) { - showRevocationWarningDialog( - (dialog, which) -> { - setPermission(group, pref, false); - if (!group.hasGrantedByDefaultPermission()) { - mHasConfirmedRevoke = true; - } - }, - grantedByDefault - ? R.string.system_warning - : R.string.old_sdk_deny_warning); - return false; - } else { - setPermission(group, pref, false); - } - } - - return true; - }); - } - return pref; - } - - private void setPermission(AppPermissionGroup group, SwitchPreference pref, boolean grant) { - if (grant) { - group.grantRuntimePermissions(false); - } else { - group.revokeRuntimePermissions(false); - } - addToggledGroup(group); - pref.setChecked(grant); - } - - private void addToggledGroup(AppPermissionGroup group) { - if (mToggledGroups == null) { - mToggledGroups = new ArraySet<>(); - } - - mToggledGroups.add(group); - } - - private void logAndClearToggledGroups() { - if (mToggledGroups != null) { - SafetyNetLogger.logPermissionsToggled(mToggledGroups); - mToggledGroups = null; - } - } - - private List<PermissionInfo> getPermissionInfosFromGroup(AppPermissionGroup group) { - ArrayList<PermissionInfo> permInfos = new ArrayList<>(group.getPermissions().size()); - for(Permission perm : group.getPermissions()) { - try { - permInfos.add(mPackageManager.getPermissionInfo(perm.getName(), 0)); - } catch (PackageManager.NameNotFoundException e) { - Log.w(LOG_TAG, "No permission:" + perm.getName()); - } - } - return permInfos; - } - - private void setPreferenceCheckedIfPresent(String preferenceKey, boolean checked) { - Preference pref = findPreference(preferenceKey); - if (pref instanceof SwitchPreference) { - ((SwitchPreference) pref).setChecked(checked); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/wear/ReviewPermissionsWearFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/wear/ReviewPermissionsWearFragment.java deleted file mode 100644 index 5aa7cafec8a82115ab85775a30cc2fbdbf429211..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/ui/wear/ReviewPermissionsWearFragment.java +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.ui.wear; - -import android.app.Activity; -import android.content.Intent; -import android.content.IntentSender; -import android.content.pm.PackageInfo; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.RemoteCallback; -import android.text.SpannableString; -import android.text.style.ForegroundColorSpan; -import android.util.Log; -import android.util.TypedValue; - -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceFragmentCompat; -import androidx.preference.PreferenceGroup; -import androidx.preference.PreferenceScreen; -import androidx.preference.SwitchPreference; -import androidx.preference.TwoStatePreference; -import androidx.wear.ble.view.WearableDialogHelper; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.AppPermissions; -import com.android.packageinstaller.permission.utils.Utils; - -import java.util.List; - -public class ReviewPermissionsWearFragment extends PreferenceFragmentCompat - implements Preference.OnPreferenceChangeListener { - private static final String TAG = "ReviewPermWear"; - - private static final int ORDER_NEW_PERMS = 1; - private static final int ORDER_CURRENT_PERMS = 2; - // Category for showing actions should be displayed last. - private static final int ORDER_ACTION = 100000; - private static final int ORDER_PERM_OFFSET_START = 100; - - private static final String EXTRA_PACKAGE_INFO = - "com.android.packageinstaller.permission.ui.extra.PACKAGE_INFO"; - - public static ReviewPermissionsWearFragment newInstance(PackageInfo packageInfo) { - Bundle arguments = new Bundle(); - arguments.putParcelable(EXTRA_PACKAGE_INFO, packageInfo); - ReviewPermissionsWearFragment instance = new ReviewPermissionsWearFragment(); - instance.setArguments(arguments); - instance.setRetainInstance(true); - return instance; - } - - private AppPermissions mAppPermissions; - - private PreferenceCategory mNewPermissionsCategory; - - private boolean mHasConfirmedRevoke; - - @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - Activity activity = getActivity(); - if (activity == null) { - return; - } - - PackageInfo packageInfo = getArguments().getParcelable(EXTRA_PACKAGE_INFO); - if (packageInfo == null) { - activity.finish(); - return; - } - - mAppPermissions = new AppPermissions(activity, packageInfo, false, - () -> getActivity().finish()); - - if (mAppPermissions.getPermissionGroups().isEmpty()) { - activity.finish(); - return; - } - - boolean reviewRequired = false; - for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { - if (group.isReviewRequired()) { - reviewRequired = true; - break; - } - } - - if (!reviewRequired) { - activity.finish(); - } - } - - @Override - public void onResume() { - super.onResume(); - mAppPermissions.refresh(); - loadPreferences(); - } - - private void loadPreferences() { - Activity activity = getActivity(); - if (activity == null) { - return; - } - - PreferenceScreen screen = getPreferenceScreen(); - if (screen == null) { - screen = getPreferenceManager().createPreferenceScreen(getActivity()); - setPreferenceScreen(screen); - } else { - screen.removeAll(); - } - - PreferenceGroup currentPermissionsCategory = null; - PreferenceGroup oldNewPermissionsCategory = mNewPermissionsCategory; - mNewPermissionsCategory = null; - - final boolean isPackageUpdated = isPackageUpdated(); - int permOrder = ORDER_PERM_OFFSET_START; - - for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { - if (!Utils.shouldShowPermission(group) - || !Utils.OS_PKG.equals(group.getDeclaringPackage())) { - continue; - } - - final SwitchPreference preference; - Preference cachedPreference = oldNewPermissionsCategory != null - ? oldNewPermissionsCategory.findPreference(group.getName()) : null; - if (cachedPreference instanceof SwitchPreference) { - preference = (SwitchPreference) cachedPreference; - } else { - preference = new SwitchPreference(getActivity()); - - preference.setKey(group.getName()); - preference.setTitle(group.getLabel()); - preference.setPersistent(false); - preference.setOrder(permOrder++); - - preference.setOnPreferenceChangeListener(this); - } - - preference.setChecked(group.areRuntimePermissionsGranted()); - - // Mutable state - if (group.isPolicyFixed()) { - preference.setEnabled(false); - } else { - preference.setEnabled(true); - } - - if (group.isReviewRequired()) { - if (!isPackageUpdated) { - // An app just being installed, which means all groups requiring reviews. - screen.addPreference(preference); - } else { - if (mNewPermissionsCategory == null) { - mNewPermissionsCategory = new PreferenceCategory(activity); - mNewPermissionsCategory.setTitle(R.string.new_permissions_category); - mNewPermissionsCategory.setOrder(ORDER_NEW_PERMS); - screen.addPreference(mNewPermissionsCategory); - } - mNewPermissionsCategory.addPreference(preference); - } - } else { - if (currentPermissionsCategory == null) { - currentPermissionsCategory = new PreferenceCategory(activity); - currentPermissionsCategory.setTitle(R.string.current_permissions_category); - currentPermissionsCategory.setOrder(ORDER_CURRENT_PERMS); - screen.addPreference(currentPermissionsCategory); - } - currentPermissionsCategory.addPreference(preference); - } - } - - addTitlePreferenceToScreen(screen); - addActionPreferencesToScreen(screen); - } - - private boolean isPackageUpdated() { - List<AppPermissionGroup> groups = mAppPermissions.getPermissionGroups(); - final int groupCount = groups.size(); - for (int i = 0; i < groupCount; i++) { - AppPermissionGroup group = groups.get(i); - if (!group.isReviewRequired()) { - return true; - } - } - return false; - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - Log.d(TAG, "onPreferenceChange " + preference.getTitle()); - if (mHasConfirmedRevoke) { - return true; - } - if (preference instanceof SwitchPreference) { - SwitchPreference switchPreference = (SwitchPreference) preference; - if (switchPreference.isChecked()) { - showWarnRevokeDialog(switchPreference); - } else { - return true; - } - } - return false; - } - - private void showWarnRevokeDialog(final SwitchPreference preference) { - // When revoking, we set "confirm" as the negative icon to be shown at the bottom. - new WearableDialogHelper.DialogBuilder(getContext()) - .setPositiveIcon(R.drawable.cancel_button) - .setNegativeIcon(R.drawable.confirm_button) - .setPositiveButton(R.string.cancel, null) - .setNegativeButton(R.string.grant_dialog_button_deny_anyway, - (dialog, which) -> { - preference.setChecked(false); - mHasConfirmedRevoke = true; - }) - .setMessage(R.string.old_sdk_deny_warning) - .show(); - } - - private void confirmPermissionsReview() { - PreferenceGroup preferenceGroup = mNewPermissionsCategory != null - ? mNewPermissionsCategory : getPreferenceScreen(); - - final int preferenceCount = preferenceGroup.getPreferenceCount(); - for (int i = 0; i < preferenceCount; i++) { - Preference preference = preferenceGroup.getPreference(i); - if (preference instanceof TwoStatePreference) { - TwoStatePreference twoStatePreference = (TwoStatePreference) preference; - String groupName = preference.getKey(); - AppPermissionGroup group = mAppPermissions.getPermissionGroup(groupName); - if (twoStatePreference.isChecked()) { - group.grantRuntimePermissions(false); - } else { - group.revokeRuntimePermissions(false); - } - group.resetReviewRequired(); - } - } - } - - private void addTitlePreferenceToScreen(PreferenceScreen screen) { - Activity activity = getActivity(); - Preference titlePref = new Preference(activity); - screen.addPreference(titlePref); - - // Set icon - Drawable icon = mAppPermissions.getPackageInfo().applicationInfo.loadIcon( - activity.getPackageManager()); - titlePref.setIcon(icon); - - // Set message - String appLabel = mAppPermissions.getAppLabel().toString(); - final int labelTemplateResId = isPackageUpdated() - ? R.string.permission_review_title_template_update - : R.string.permission_review_title_template_install; - SpannableString message = new SpannableString(getString(labelTemplateResId, appLabel)); - - // Color the app name. - final int appLabelStart = message.toString().indexOf(appLabel, 0); - final int appLabelLength = appLabel.length(); - - TypedValue typedValue = new TypedValue(); - activity.getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true); - final int color = activity.getColor(typedValue.resourceId); - - message.setSpan(new ForegroundColorSpan(color), appLabelStart, - appLabelStart + appLabelLength, 0); - - titlePref.setTitle(message); - - titlePref.setSelectable(false); - titlePref.setLayoutResource(R.layout.wear_review_permission_title_pref); - } - - private void addActionPreferencesToScreen(PreferenceScreen screen) { - final Activity activity = getActivity(); - - Preference cancelPref = new Preference(activity); - cancelPref.setTitle(R.string.review_button_cancel); - cancelPref.setOrder(ORDER_ACTION); - cancelPref.setEnabled(true); - cancelPref.setLayoutResource(R.layout.wear_review_permission_action_pref); - cancelPref.setOnPreferenceClickListener(p -> { - executeCallback(false); - activity.setResult(Activity.RESULT_CANCELED); - activity.finish(); - return true; - }); - screen.addPreference(cancelPref); - - Preference continuePref = new Preference(activity); - continuePref.setTitle(R.string.review_button_continue); - continuePref.setOrder(ORDER_ACTION + 1); - continuePref.setEnabled(true); - continuePref.setLayoutResource(R.layout.wear_review_permission_action_pref); - continuePref.setOnPreferenceClickListener(p -> { - confirmPermissionsReview(); - executeCallback(true); - getActivity().finish(); - return true; - }); - screen.addPreference(continuePref); - } - - private void executeCallback(boolean success) { - Activity activity = getActivity(); - if (activity == null) { - return; - } - if (success) { - IntentSender intent = activity.getIntent().getParcelableExtra(Intent.EXTRA_INTENT); - if (intent != null) { - try { - int flagMask = 0; - int flagValues = 0; - if (activity.getIntent().getBooleanExtra( - Intent.EXTRA_RESULT_NEEDED, false)) { - flagMask = Intent.FLAG_ACTIVITY_FORWARD_RESULT; - flagValues = Intent.FLAG_ACTIVITY_FORWARD_RESULT; - } - activity.startIntentSenderForResult(intent, -1, null, - flagMask, flagValues, 0); - } catch (IntentSender.SendIntentException e) { - /* ignore */ - } - return; - } - } - RemoteCallback callback = activity.getIntent().getParcelableExtra( - Intent.EXTRA_REMOTE_CALLBACK); - if (callback != null) { - Bundle result = new Bundle(); - result.putBoolean(Intent.EXTRA_RETURN_RESULT, success); - callback.sendResult(result); - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/ArrayUtils.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/ArrayUtils.java deleted file mode 100644 index 2af641bc321c2f6f447e191e6b3b79d291b6af99..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/ArrayUtils.java +++ /dev/null @@ -1,63 +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.utils; - -import android.text.TextUtils; - -import java.util.Objects; - -public final class ArrayUtils { - private ArrayUtils() { /* cannot be instantiated */ } - - /** - * Checks that value is present as at least one of the elements of the array. - * @param array the array to check in - * @param value the value to check for - * @return true if the value is present in the array - */ - public static <T> boolean contains(T[] array, T value) { - return indexOf(array, value) != -1; - } - - /** - * Return first index of {@code value} in {@code array}, or {@code -1} if - * not found. - */ - public static <T> int indexOf(T[] array, T value) { - if (array == null) return -1; - for (int i = 0; i < array.length; i++) { - if (Objects.equals(array[i], value)) return i; - } - return -1; - } - - public static String[] appendString(String[] cur, String val) { - if (cur == null) { - return new String[] { val }; - } - final int N = cur.length; - for (int i = 0; i < N; i++) { - if (TextUtils.equals(cur[i], val)) { - return cur; - } - } - String[] ret = new String[N + 1]; - System.arraycopy(cur, 0, ret, 0, N); - ret[N] = val; - return ret; - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/EventLogger.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/EventLogger.java deleted file mode 100644 index 7aff7ada792d58e39d941391c03c53ae35d68bb0..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/EventLogger.java +++ /dev/null @@ -1,43 +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.utils; - -import android.metrics.LogMaker; -import androidx.annotation.NonNull; - -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; - -public class EventLogger { - private static final MetricsLogger sMetricsLogger = new MetricsLogger(); - - /** - * Log that a permission was requested/denied. - * - * @param action the action performed - * @param name name of the permission - * @param packageName package permission is for - */ - public static void logPermission(int action, @NonNull String name, - @NonNull String packageName) { - final LogMaker log = new LogMaker(action); - log.setPackageName(packageName); - log.addTaggedData(MetricsEvent.FIELD_PERMISSION, name); - - sMetricsLogger.write(log); - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/IoUtils.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/IoUtils.java deleted file mode 100644 index ff7d1831519f988f020402608d4fc72ffb95f9b3..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/IoUtils.java +++ /dev/null @@ -1,36 +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.utils; - -public final class IoUtils { - private IoUtils() { - } - - /** - * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null. - */ - public static void closeQuietly(AutoCloseable closeable) { - if (closeable != null) { - try { - closeable.close(); - } catch (RuntimeException rethrown) { - throw rethrown; - } catch (Exception ignored) { - } - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/LocationUtils.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/LocationUtils.java deleted file mode 100644 index 0296ae80ad4c7097ce571f15fb77f42e245356f8..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/LocationUtils.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.packageinstaller.permission.utils; - -import android.Manifest; -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.content.res.Resources; -import android.location.ILocationManager; -import android.location.LocationManager; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.provider.Settings; - -import com.android.packageinstaller.R; - -import java.util.ArrayList; - -public class LocationUtils { - - public static final String LOCATION_PERMISSION = Manifest.permission_group.LOCATION; - - public static void showLocationDialog(final Context context, CharSequence label) { - new AlertDialog.Builder(context) - .setIcon(R.drawable.ic_dialog_alert_material) - .setTitle(android.R.string.dialog_alert_title) - .setMessage(context.getString(R.string.location_warning, label)) - .setNegativeButton(R.string.ok, null) - .setPositiveButton(R.string.location_settings, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - context.startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); - } - }) - .show(); - } - - public static boolean isLocationEnabled(Context context) { - return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE, - Settings.Secure.LOCATION_MODE_OFF) != Settings.Secure.LOCATION_MODE_OFF; - } - - public static boolean isLocationGroupAndProvider(String groupName, String packageName) { - return LOCATION_PERMISSION.equals(groupName) && isNetworkLocationProvider(packageName); - } - - private static boolean isNetworkLocationProvider(String packageName) { - ILocationManager locationService = ILocationManager.Stub.asInterface( - ServiceManager.getService(Context.LOCATION_SERVICE)); - try { - return packageName.equals(locationService.getNetworkProviderPackage()); - } catch (RemoteException e) { - return false; - } - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/SafetyNetLogger.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/SafetyNetLogger.java deleted file mode 100644 index 7773294b0998c7387cb81f6839d151ab043f99ef..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/SafetyNetLogger.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.utils; - -import android.content.pm.PackageInfo; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.EventLog; - -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.Permission; - -import java.util.ArrayList; -import java.util.List; - -public final class SafetyNetLogger { - - // The log tag used by SafetyNet to pick entries from the event log. - private static final int SNET_NET_EVENT_LOG_TAG = 0x534e4554; - - // Log tag for the result of permissions request. - private static final String PERMISSIONS_REQUESTED = "individual_permissions_requested"; - - // Log tag for the result of permissions toggling. - private static final String PERMISSIONS_TOGGLED = "individual_permissions_toggled"; - - private SafetyNetLogger() { - /* do nothing */ - } - - public static void logPermissionsRequested(PackageInfo packageInfo, - List<AppPermissionGroup> groups) { - EventLog.writeEvent(SNET_NET_EVENT_LOG_TAG, PERMISSIONS_REQUESTED, - packageInfo.applicationInfo.uid, buildChangedPermissionForPackageMessage( - packageInfo.packageName, groups)); - } - - /** - * Log that permission groups have been toggled for the purpose of safety net. - * - * <p>The groups might refer to different permission groups and different apps. - * - * @param groups The groups toggled - */ - public static void logPermissionsToggled(ArraySet<AppPermissionGroup> groups) { - ArrayMap<String, ArrayList<AppPermissionGroup>> groupsByPackage = new ArrayMap<>(); - - int numGroups = groups.size(); - for (int i = 0; i < numGroups; i++) { - AppPermissionGroup group = groups.valueAt(i); - - ArrayList<AppPermissionGroup> groupsForThisPackage = groupsByPackage.get( - group.getApp().packageName); - if (groupsForThisPackage == null) { - groupsForThisPackage = new ArrayList<>(); - groupsByPackage.put(group.getApp().packageName, groupsForThisPackage); - } - - groupsForThisPackage.add(group); - if (group.getBackgroundPermissions() != null) { - groupsForThisPackage.add(group.getBackgroundPermissions()); - } - } - - int numPackages = groupsByPackage.size(); - for (int i = 0; i < numPackages; i++) { - EventLog.writeEvent(SNET_NET_EVENT_LOG_TAG, PERMISSIONS_TOGGLED, - android.os.Process.myUid(), buildChangedPermissionForPackageMessage( - groupsByPackage.keyAt(i), groupsByPackage.valueAt(i))); - } - } - - private static void buildChangedPermissionForGroup(AppPermissionGroup group, - StringBuilder builder) { - int permissionCount = group.getPermissions().size(); - for (int permissionNum = 0; permissionNum < permissionCount; permissionNum++) { - Permission permission = group.getPermissions().get(permissionNum); - - if (builder.length() > 0) { - builder.append(';'); - } - - builder.append(permission.getName()).append('|'); - - if (group.doesSupportRuntimePermissions()) { - builder.append(permission.isGranted()).append('|'); - } else { - builder.append(permission.isGranted() - && (!permission.affectsAppOp() || permission.isAppOpAllowed())).append('|'); - } - - builder.append(permission.getFlags()); - } - } - - private static String buildChangedPermissionForPackageMessage(String packageName, - List<AppPermissionGroup> groups) { - StringBuilder builder = new StringBuilder(); - - builder.append(packageName).append(':'); - - int groupCount = groups.size(); - for (int groupNum = 0; groupNum < groupCount; groupNum++) { - AppPermissionGroup group = groups.get(groupNum); - - buildChangedPermissionForGroup(group, builder); - if (group.getBackgroundPermissions() != null) { - buildChangedPermissionForGroup(group.getBackgroundPermissions(), builder); - } - } - - return builder.toString(); - } -} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/Utils.java b/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/Utils.java deleted file mode 100644 index d7ee219b0e470a331043a0793659235b7d6aec39..0000000000000000000000000000000000000000 --- a/packages/PackageInstaller/src/com/android/packageinstaller/permission/utils/Utils.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.packageinstaller.permission.utils; - -import android.Manifest; -import android.annotation.StringRes; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.res.Resources; -import android.content.res.Resources.Theme; -import android.graphics.drawable.Drawable; -import android.text.Html; -import android.util.ArraySet; -import android.util.Log; -import android.util.TypedValue; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.AppPermissionGroup; -import com.android.packageinstaller.permission.model.AppPermissions; -import com.android.packageinstaller.permission.model.PermissionApps.PermissionApp; - -import java.util.List; - -public final class Utils { - - private static final String LOG_TAG = "Utils"; - - public static final String OS_PKG = "android"; - - public static final String[] MODERN_PERMISSION_GROUPS = { - Manifest.permission_group.CALENDAR, - Manifest.permission_group.CALL_LOG, - Manifest.permission_group.CAMERA, - Manifest.permission_group.CONTACTS, - Manifest.permission_group.LOCATION, - Manifest.permission_group.SENSORS, - Manifest.permission_group.SMS, - Manifest.permission_group.PHONE, - Manifest.permission_group.MICROPHONE, - Manifest.permission_group.STORAGE - }; - - private static final Intent LAUNCHER_INTENT = new Intent(Intent.ACTION_MAIN, null) - .addCategory(Intent.CATEGORY_LAUNCHER); - - private Utils() { - /* do nothing - hide constructor */ - } - - public static Drawable loadDrawable(PackageManager pm, String pkg, int resId) { - try { - return pm.getResourcesForApplication(pkg).getDrawable(resId, null); - } catch (Resources.NotFoundException | PackageManager.NameNotFoundException e) { - Log.d(LOG_TAG, "Couldn't get resource", e); - return null; - } - } - - public static boolean isModernPermissionGroup(String name) { - for (String modernGroup : MODERN_PERMISSION_GROUPS) { - if (modernGroup.equals(name)) { - return true; - } - } - return false; - } - - /** - * Should UI show this permission. - * - * <p>If the user cannot change the group, it should not be shown. - * - * @param group The group that might need to be shown to the user - * - * @return - */ - public static boolean shouldShowPermission(AppPermissionGroup group) { - boolean isSystemFixed = group.isSystemFixed(); - if (group.getBackgroundPermissions() != null) { - // If the foreground mode is fixed to "enabled", the background mode might still be - // switchable. We only want to suppress the group if nothing can be switched - if (group.areRuntimePermissionsGranted()) { - isSystemFixed &= group.getBackgroundPermissions().isSystemFixed(); - } - } - - // We currently will not show permissions fixed by the system. - // which is what the system does for system components. - if (isSystemFixed && !LocationUtils.isLocationGroupAndProvider( - group.getName(), group.getApp().packageName)) { - return false; - } - - if (!group.isGrantingAllowed()) { - return false; - } - - final boolean isPlatformPermission = group.getDeclaringPackage().equals(OS_PKG); - // Show legacy permissions only if the user chose that. - if (isPlatformPermission - && !Utils.isModernPermissionGroup(group.getName())) { - return false; - } - return true; - } - - public static Drawable applyTint(Context context, Drawable icon, int attr) { - Theme theme = context.getTheme(); - TypedValue typedValue = new TypedValue(); - theme.resolveAttribute(attr, typedValue, true); - icon = icon.mutate(); - icon.setTint(context.getColor(typedValue.resourceId)); - return icon; - } - - public static Drawable applyTint(Context context, int iconResId, int attr) { - return applyTint(context, context.getDrawable(iconResId), attr); - } - - public static ArraySet<String> getLauncherPackages(Context context) { - ArraySet<String> launcherPkgs = new ArraySet<>(); - for (ResolveInfo info : - context.getPackageManager().queryIntentActivities(LAUNCHER_INTENT, 0)) { - launcherPkgs.add(info.activityInfo.packageName); - } - - return launcherPkgs; - } - - public static List<ApplicationInfo> getAllInstalledApplications(Context context) { - return context.getPackageManager().getInstalledApplications(0); - } - - public static boolean isSystem(PermissionApp app, ArraySet<String> launcherPkgs) { - return isSystem(app.getAppInfo(), launcherPkgs); - } - - public static boolean isSystem(AppPermissions app, ArraySet<String> launcherPkgs) { - return isSystem(app.getPackageInfo().applicationInfo, launcherPkgs); - } - - public static boolean isSystem(ApplicationInfo info, ArraySet<String> launcherPkgs) { - return info.isSystemApp() && (info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0 - && !launcherPkgs.contains(info.packageName); - } - - public static boolean areGroupPermissionsIndividuallyControlled(Context context, String group) { - if (!context.getPackageManager().arePermissionsIndividuallyControlled()) { - return false; - } - return Manifest.permission_group.SMS.equals(group) - || Manifest.permission_group.PHONE.equals(group) - || Manifest.permission_group.CONTACTS.equals(group); - } - - public static boolean isPermissionIndividuallyControlled(Context context, String permission) { - if (!context.getPackageManager().arePermissionsIndividuallyControlled()) { - return false; - } - return Manifest.permission.READ_CONTACTS.equals(permission) - || Manifest.permission.WRITE_CONTACTS.equals(permission) - || Manifest.permission.SEND_SMS.equals(permission) - || Manifest.permission.RECEIVE_SMS.equals(permission) - || Manifest.permission.READ_SMS.equals(permission) - || Manifest.permission.RECEIVE_MMS.equals(permission) - || Manifest.permission.CALL_PHONE.equals(permission) - || Manifest.permission.READ_CALL_LOG.equals(permission) - || Manifest.permission.WRITE_CALL_LOG.equals(permission); - } - - /** - * Get the message shown to grant a permission group to an app. - * - * @param appLabel The label of the app - * @param group the group to be granted - * @param context A context to resolve resources - * @param requestRes The resource id of the grant request message - * - * @return The formatted message to be used as title when granting permissions - */ - public static CharSequence getRequestMessage(CharSequence appLabel, AppPermissionGroup group, - Context context, @StringRes int requestRes) { - if (requestRes != 0) { - try { - return Html.fromHtml(context.getPackageManager().getResourcesForApplication( - group.getDeclaringPackage()).getString(requestRes, appLabel), 0); - } catch (PackageManager.NameNotFoundException ignored) { - } - } - - return Html.fromHtml(context.getString(R.string.permission_warning_template, appLabel, - group.getDescription()), 0); - } -} diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ac33454c84ad0337d8ef61e9b5036d98b50ea391..d299930506d891dd310ed81b858384743bcdeaf3 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3241,7 +3241,7 @@ public class PackageManagerService extends IPackageManager.Stub mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr( PackageManager.SYSTEM_SHARED_LIBRARY_SHARED, SharedLibraryInfo.VERSION_UNDEFINED); - mRequiredPermissionControllerPackage = getRequiredPermissionsControllerLPr(); + mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr(); } else { mRequiredVerifierPackage = null; mRequiredInstallerPackage = null; @@ -3598,7 +3598,7 @@ public class PackageManagerService extends IPackageManager.Stub return resolveInfo.getComponentInfo().packageName; } - private @NonNull String getRequiredPermissionsControllerLPr() { + private @NonNull String getRequiredPermissionControllerLPr() { final Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSIONS); intent.addCategory(Intent.CATEGORY_DEFAULT); @@ -23972,6 +23972,8 @@ public class PackageManagerService extends IPackageManager.Stub return mRequiredVerifierPackage; case PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER: return mSystemTextClassifierPackage; + case PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER: + return mRequiredPermissionControllerPackage; } return null; } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 76832ed3f4f9731cbe0526e80be87db56f1e6597..9dc0b296f97e6e9f4b39c92b766a1fa0ff970f00 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1267,9 +1267,15 @@ public class PermissionManagerService { // we still want to blindly grant it to old apps. allowed = true; } + // TODO (moltmann): The installer now shares the platforms signature. Hence it does not + // need a separate flag anymore. Hence we need to check which + // permissions are needed by the permission controller if (!allowed && bp.isInstaller() - && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( - PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM))) { + && (pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM)) + || pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER, + UserHandle.USER_SYSTEM)))) { // If this permission is to be granted to the system installer and // this app is an installer, then it gets the permission. allowed = true;