summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/layout/car_default_app_frame.xml55
-rw-r--r--res/layout/car_settings_frame.xml90
-rw-r--r--res/values/styles.xml2
-rw-r--r--src/com/android/packageinstaller/auto/AutoSettingsFrameFragment.java121
-rw-r--r--src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java32
-rw-r--r--src/com/android/packageinstaller/permission/ui/auto/AutoAppPermissionsFragment.java388
6 files changed, 624 insertions, 64 deletions
diff --git a/res/layout/car_default_app_frame.xml b/res/layout/car_default_app_frame.xml
deleted file mode 100644
index 2fe0856e..00000000
--- a/res/layout/car_default_app_frame.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT 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="match_parent"
- android:orientation="vertical">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="@dimen/car_action_bar_height"
- android:gravity="center_vertical"
- android:orientation="horizontal">
- <FrameLayout
- android:id="@+id/back_button"
- android:layout_width="@dimen/car_margin"
- android:layout_height="match_parent">
- <ImageView
- android:layout_width="@dimen/car_icon_size"
- android:layout_height="@dimen/car_icon_size"
- android:layout_gravity="center"
- android:scaleType="fitCenter"
- android:src="@drawable/ic_arrow_back"
- android:tint="?android:attr/textColorPrimary"/>
- </FrameLayout>
-
- <TextView
- android:id="@+id/label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceLarge"/>
- </LinearLayout>
-
- <FrameLayout
- android:id="@android:id/list_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingEnd="@dimen/car_margin"
- android:paddingStart="@dimen/car_margin"/>
-</LinearLayout>
diff --git a/res/layout/car_settings_frame.xml b/res/layout/car_settings_frame.xml
new file mode 100644
index 00000000..4381d014
--- /dev/null
+++ b/res/layout/car_settings_frame.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="@*android:dimen/car_app_bar_height">
+
+ <FrameLayout
+ android:id="@+id/back_button"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:background="?android:attr/selectableItemBackground"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@+id/start_margin"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+ <ImageView
+ android:layout_width="@*android:dimen/car_primary_icon_size"
+ android:layout_height="@*android:dimen/car_primary_icon_size"
+ android:layout_gravity="center"
+ android:scaleType="fitCenter"
+ android:src="@drawable/ic_arrow_back"
+ android:tint="?android:attr/textColorPrimary"/>
+ </FrameLayout>
+
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/start_margin"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ app:layout_constraintGuide_begin="@*android:dimen/action_bar_margin_start"/>
+
+ <TextView
+ android:id="@+id/label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/start_margin"
+ app:layout_constraintTop_toTopOf="parent"/>
+
+ <Button
+ android:id="@+id/action"
+ style="@*android:style/ActionBarButton"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_marginEnd="@*android:dimen/action_bar_button_margin"
+ android:visibility="gone"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"/>
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <ProgressBar
+ android:id="@+id/progress_bar"
+ style="@android:style/Widget.DeviceDefault.ProgressBar.Horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:indeterminate="true"
+ android:visibility="gone"/>
+
+ <FrameLayout
+ android:id="@android:id/list_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingEnd="@*android:dimen/car_margin"
+ android:paddingStart="@*android:dimen/car_margin"/>
+</LinearLayout>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index b8fbc380..6469cbd9 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -861,7 +861,7 @@
<!-- START CAR SETTINGS PREFERENCE STYLES -->
<style name="CarPreferenceFragment">
- <item name="android:layout">@layout/car_default_app_frame</item>
+ <item name="android:layout">@layout/car_settings_frame</item>
</style>
<style name="CarPreferenceFragmentList">
diff --git a/src/com/android/packageinstaller/auto/AutoSettingsFrameFragment.java b/src/com/android/packageinstaller/auto/AutoSettingsFrameFragment.java
new file mode 100644
index 00000000..ea8987e3
--- /dev/null
+++ b/src/com/android/packageinstaller/auto/AutoSettingsFrameFragment.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto;
+
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.preference.PreferenceFragmentCompat;
+
+import com.android.permissioncontroller.R;
+
+/** Common settings frame for car related settings in permission controller. */
+public abstract class AutoSettingsFrameFragment extends PreferenceFragmentCompat {
+
+ private TextView mLabelView;
+ private ProgressBar mProgressBar;
+ private Button mAction;
+
+ private CharSequence mLabel;
+ private boolean mIsLoading;
+ private CharSequence mActionLabel;
+ private View.OnClickListener mActionOnClickListener;
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ View rootView = super.onCreateView(inflater, container, savedInstanceState);
+
+ View backButton = rootView.findViewById(R.id.back_button);
+ backButton.setOnClickListener(v -> getActivity().onBackPressed());
+
+ mLabelView = rootView.findViewById(R.id.label);
+ updateHeaderLabel();
+
+ mProgressBar = rootView.findViewById(R.id.progress_bar);
+ updateLoading();
+
+ mAction = rootView.findViewById(R.id.action);
+ updateAction();
+
+ return rootView;
+ }
+
+ /** Sets the header text of this fragment. */
+ public void setHeaderLabel(CharSequence label) {
+ mLabel = label;
+ updateHeaderLabel();
+ }
+
+ /** Gets the header text of this fragment. */
+ public CharSequence getHeaderLabel() {
+ return mLabel;
+ }
+
+ private void updateHeaderLabel() {
+ if (mLabelView != null) {
+ mLabelView.setText(mLabel);
+ }
+ }
+
+ /**
+ * Shows a progress view while content is loading.
+ *
+ * @param isLoading {@code true} if the progress view should be visible.
+ */
+ public void setLoading(boolean isLoading) {
+ mIsLoading = isLoading;
+ updateLoading();
+ }
+
+ private void updateLoading() {
+ if (mProgressBar != null) {
+ mProgressBar.setVisibility(mIsLoading ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ /**
+ * Shows a button with the given {@code label} that when clicked will call the given {@code
+ * onClickListener}.
+ */
+ public void setAction(CharSequence label, View.OnClickListener onClickListener) {
+ mActionLabel = label;
+ mActionOnClickListener = onClickListener;
+ updateAction();
+ }
+
+ private void updateAction() {
+ if (mAction == null) {
+ return;
+ }
+ if (!TextUtils.isEmpty(mActionLabel) && mActionOnClickListener != null) {
+ mAction.setText(mActionLabel);
+ mAction.setOnClickListener(mActionOnClickListener);
+ mAction.setVisibility(View.VISIBLE);
+ } else {
+ mAction.setVisibility(View.GONE);
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java b/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
index b15127cf..7d0b8c91 100644
--- a/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
+++ b/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
@@ -28,10 +28,12 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import com.android.packageinstaller.DeviceUtils;
+import com.android.packageinstaller.permission.ui.auto.AutoAppPermissionsFragment;
import com.android.packageinstaller.permission.ui.handheld.ManageStandardPermissionsFragment;
import com.android.packageinstaller.permission.ui.handheld.PermissionUsageFragment;
import com.android.packageinstaller.permission.ui.wear.AppPermissionsFragmentWear;
import com.android.packageinstaller.permission.utils.Utils;
+import com.android.permissioncontroller.R;
public final class ManagePermissionsActivity extends FragmentActivity {
private static final String LOG_TAG = ManagePermissionsActivity.class.getSimpleName();
@@ -41,6 +43,11 @@ public final class ManagePermissionsActivity extends FragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
+ if (DeviceUtils.isAuto(this)) {
+ // Automotive relies on a different theme. Apply before calling super so that
+ // fragments are restored properly on configuration changes.
+ setTheme(R.style.CarSettings);
+ }
super.onCreate(savedInstanceState);
// If there is a previous instance, re-use its Fragment instead of making a new one.
@@ -103,21 +110,30 @@ public final class ManagePermissionsActivity extends FragmentActivity {
finish();
return;
}
+
+ final boolean allPermissions = getIntent().getBooleanExtra(
+ EXTRA_ALL_PERMISSIONS, false);
+
+ UserHandle userHandle = getIntent().getParcelableExtra(Intent.EXTRA_USER);
+ if (userHandle == null) {
+ userHandle = UserHandle.of(UserHandle.myUserId());
+ }
+
if (DeviceUtils.isAuto(this)) {
- fragment = com.android.packageinstaller.permission.ui.auto
- .AppPermissionsFragment.newInstance(packageName);
+ if (allPermissions) {
+ // TODO: Replace this with a car version.
+ androidXFragment = com.android.packageinstaller.permission.ui.handheld
+ .AllAppPermissionsFragment.newInstance(packageName, userHandle);
+ } else {
+ androidXFragment = AutoAppPermissionsFragment.newInstance(packageName,
+ userHandle);
+ }
} else if (DeviceUtils.isWear(this)) {
androidXFragment = 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);
- UserHandle userHandle = getIntent().getParcelableExtra(Intent.EXTRA_USER);
- if (userHandle == null) {
- userHandle = UserHandle.of(UserHandle.myUserId());
- }
if (allPermissions) {
androidXFragment = com.android.packageinstaller.permission.ui.handheld
.AllAppPermissionsFragment.newInstance(packageName, userHandle);
diff --git a/src/com/android/packageinstaller/permission/ui/auto/AutoAppPermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/auto/AutoAppPermissionsFragment.java
new file mode 100644
index 00000000..4f596ef0
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/auto/AutoAppPermissionsFragment.java
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.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.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+
+import com.android.packageinstaller.auto.AutoSettingsFrameFragment;
+import com.android.packageinstaller.permission.model.AppPermissionGroup;
+import com.android.packageinstaller.permission.model.AppPermissions;
+import com.android.packageinstaller.permission.model.PermissionUsages;
+import com.android.packageinstaller.permission.ui.AppPermissionActivity;
+import com.android.packageinstaller.permission.ui.handheld.AllAppPermissionsFragment;
+import com.android.packageinstaller.permission.utils.Utils;
+import com.android.permissioncontroller.R;
+
+import java.text.Collator;
+import java.util.ArrayList;
+
+/** Screen to show the permissions for a specific application. */
+public class AutoAppPermissionsFragment extends AutoSettingsFrameFragment {
+ private static final String LOG_TAG = "ManagePermsFragment";
+
+ static final String EXTRA_HIDE_INFO_BUTTON = "hideInfoButton";
+ private static final String KEY_APP_INFO_INTENT = "key_app_info_intent";
+ private static final String KEY_USER_HANDLE = "key_user_handle";
+ private static final String KEY_ALLOWED_PERMISSIONS_GROUP = "allowed_permissions_group";
+ private static final String KEY_DENIED_PERMISSIONS_GROUP = "denied_permissions_group";
+
+ private AppPermissions mAppPermissions;
+ private PreferenceScreen mExtraScreen;
+
+ private Collator mCollator;
+
+ /**
+ * @return A new fragment
+ */
+ public static AutoAppPermissionsFragment newInstance(@NonNull String packageName,
+ @NonNull UserHandle userHandle) {
+ return setPackageNameAndUserHandle(new AutoAppPermissionsFragment(), packageName,
+ userHandle);
+ }
+
+ private static <T extends Fragment> T setPackageNameAndUserHandle(@NonNull T fragment,
+ @NonNull String packageName, @NonNull UserHandle userHandle) {
+ Bundle arguments = new Bundle();
+ arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
+ arguments.putParcelable(Intent.EXTRA_USER, userHandle);
+ fragment.setArguments(arguments);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setLoading(true);
+
+ String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
+ UserHandle userHandle = getArguments().getParcelable(Intent.EXTRA_USER);
+ Activity activity = getActivity();
+ PackageInfo packageInfo = getPackageInfo(activity, packageName, userHandle);
+ if (packageInfo == null) {
+ Toast.makeText(getContext(), R.string.app_not_found_dlg_title,
+ Toast.LENGTH_LONG).show();
+ activity.finish();
+ return;
+ }
+
+ setHeaderLabel(getContext().getString(R.string.app_permissions));
+ setAction(getContext().getString(R.string.all_permissions), v -> showAllPermissions());
+
+ mAppPermissions = new AppPermissions(activity, packageInfo, /* sortGroups= */ true,
+ () -> getActivity().finish());
+
+ mCollator = Collator.getInstance(
+ getContext().getResources().getConfiguration().getLocales().get(0));
+ }
+
+ @Override
+ public void onCreatePreferences(Bundle bundle, String s) {
+ setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getContext()));
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ bindUi(mAppPermissions.getPackageInfo());
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ mAppPermissions.refresh();
+ updatePreferences();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ getPreferenceScreen().removeAll();
+ }
+
+ private void showAllPermissions() {
+ Fragment frag = AllAppPermissionsFragment.newInstance(
+ getArguments().getString(Intent.EXTRA_PACKAGE_NAME),
+ getArguments().getParcelable(Intent.EXTRA_USER));
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, frag)
+ .addToBackStack("AllPerms")
+ .commit();
+ }
+
+ protected void bindUi(PackageInfo packageInfo) {
+ addAppHeaderPreference(requireActivity(), getPreferenceScreen(), packageInfo);
+
+ PreferenceGroup allowed = new PreferenceCategory(getContext());
+ allowed.setKey(KEY_ALLOWED_PERMISSIONS_GROUP);
+ allowed.setTitle(R.string.allowed_header);
+ getPreferenceScreen().addPreference(allowed);
+
+ PreferenceGroup denied = new PreferenceCategory(getContext());
+ denied.setKey(KEY_DENIED_PERMISSIONS_GROUP);
+ denied.setTitle(R.string.denied_header);
+ getPreferenceScreen().addPreference(denied);
+ }
+
+ private void updatePreferences() {
+ Context context = getPreferenceManager().getContext();
+ if (context == null) {
+ return;
+ }
+
+ PreferenceCategory allowed = findPreference(KEY_ALLOWED_PERMISSIONS_GROUP);
+ PreferenceCategory denied = findPreference(KEY_DENIED_PERMISSIONS_GROUP);
+
+ allowed.removeAll();
+ denied.removeAll();
+
+ if (mExtraScreen != null) {
+ mExtraScreen.removeAll();
+ addAppHeaderPreference(requireActivity(), mExtraScreen,
+ mAppPermissions.getPackageInfo());
+ }
+
+ Preference extraPerms = new Preference(context);
+ extraPerms.setIcon(R.drawable.ic_toc);
+ extraPerms.setTitle(R.string.additional_permissions);
+ boolean extraPermsAreAllowed = false;
+
+ ArrayList<AppPermissionGroup> groups = new ArrayList<>(
+ mAppPermissions.getPermissionGroups());
+ groups.sort((x, y) -> mCollator.compare(x.getLabel(), y.getLabel()));
+ allowed.setOrderingAsAdded(true);
+ denied.setOrderingAsAdded(true);
+
+ for (int i = 0; i < groups.size(); i++) {
+ AppPermissionGroup group = groups.get(i);
+ if (!Utils.shouldShowPermission(getContext(), group)) {
+ continue;
+ }
+
+ boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG);
+
+ Preference preference = createPermissionPreference(getContext(), group);
+ if (isPlatform) {
+ PreferenceCategory category =
+ group.areRuntimePermissionsGranted() ? allowed : denied;
+ category.addPreference(preference);
+ } else {
+ if (mExtraScreen == null) {
+ mExtraScreen = getPreferenceManager().createPreferenceScreen(context);
+ addAppHeaderPreference(requireActivity(), mExtraScreen,
+ mAppPermissions.getPackageInfo());
+ }
+ mExtraScreen.addPreference(preference);
+ if (group.areRuntimePermissionsGranted()) {
+ extraPermsAreAllowed = true;
+ }
+ }
+ }
+
+ if (mExtraScreen != null) {
+ extraPerms.setOnPreferenceClickListener(preference -> {
+ AutoAppPermissionsFragment.AdditionalPermissionsFragment
+ frag = new AutoAppPermissionsFragment.AdditionalPermissionsFragment();
+ setPackageNameAndUserHandle(frag,
+ getArguments().getString(Intent.EXTRA_PACKAGE_NAME),
+ getArguments().getParcelable(Intent.EXTRA_USER));
+ frag.setTargetFragment(AutoAppPermissionsFragment.this, 0);
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, frag)
+ .addToBackStack(null)
+ .commit();
+ return true;
+ });
+ // Delete 1 to account for app header preference.
+ int count = mExtraScreen.getPreferenceCount() - 1;
+ extraPerms.setSummary(getResources().getQuantityString(
+ R.plurals.additional_permissions_more, count,
+ count));
+ PreferenceCategory category = extraPermsAreAllowed ? allowed : denied;
+ category.addPreference(extraPerms);
+ }
+
+ if (allowed.getPreferenceCount() == 0) {
+ Preference empty = new Preference(context);
+ empty.setTitle(getString(R.string.no_permissions_allowed));
+ empty.setSelectable(false);
+ allowed.addPreference(empty);
+ }
+ if (denied.getPreferenceCount() == 0) {
+ Preference empty = new Preference(context);
+ empty.setTitle(getString(R.string.no_permissions_denied));
+ empty.setSelectable(false);
+ denied.addPreference(empty);
+ }
+
+ setLoading(false);
+ }
+
+ private PackageInfo getPackageInfo(Activity activity, @NonNull String packageName,
+ @NonNull UserHandle userHandle) {
+ try {
+ return activity.createPackageContextAsUser(packageName, 0,
+ userHandle).getPackageManager().getPackageInfo(packageName,
+ PackageManager.GET_PERMISSIONS);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e);
+ return null;
+ }
+ }
+
+ private void addAppHeaderPreference(Activity activity, PreferenceScreen screen,
+ PackageInfo packageInfo) {
+ // Only add the app header if it is the first preference to be added.
+ if (screen.getPreferenceCount() != 0) {
+ Log.e(LOG_TAG, "cannot add app header, since screen is already populated");
+ return;
+ }
+
+ 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));
+ }
+
+ Preference preference = createHeaderPreference(activity, infoIntent,
+ packageInfo.applicationInfo);
+ screen.addPreference(preference);
+ }
+
+ private Preference createHeaderPreference(Context context, Intent infoIntent,
+ ApplicationInfo appInfo) {
+ Drawable icon = Utils.getBadgedIcon(context, appInfo);
+ Preference preference = new Preference(context);
+ preference.setIcon(icon);
+ preference.setKey(appInfo.packageName);
+ preference.setTitle(Utils.getFullAppLabel(appInfo, context));
+ preference.getExtras().putParcelable(KEY_APP_INFO_INTENT, infoIntent);
+ preference.getExtras().putParcelable(KEY_USER_HANDLE,
+ UserHandle.getUserHandleForUid(appInfo.uid));
+ preference.setOnPreferenceClickListener(pref -> {
+ Intent intent = pref.getExtras().getParcelable(KEY_APP_INFO_INTENT);
+ UserHandle user = pref.getExtras().getParcelable(KEY_USER_HANDLE);
+ context.startActivityAsUser(intent, user);
+ return true;
+ });
+ return preference;
+ }
+
+ private Preference createPermissionPreference(Context context, AppPermissionGroup group) {
+ Preference preference = new Preference(context);
+ Drawable icon = Utils.loadDrawable(context.getPackageManager(),
+ group.getIconPkg(), group.getIconResId());
+ preference.setKey(group.getName());
+ preference.setTitle(group.getFullLabel());
+ preference.setIcon(Utils.applyTint(context, icon, android.R.attr.colorControlNormal));
+ preference.setSummary(getPreferenceSummary(group));
+ preference.setOnPreferenceClickListener(pref -> {
+ Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSION);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, group.getApp().packageName);
+ intent.putExtra(Intent.EXTRA_PERMISSION_NAME, group.getPermissions().get(0).getName());
+ intent.putExtra(Intent.EXTRA_USER, group.getUser());
+ intent.putExtra(AppPermissionActivity.EXTRA_CALLER_NAME,
+ AutoAppPermissionsFragment.class.getName());
+ context.startActivity(intent);
+ return true;
+ });
+ return preference;
+ }
+
+ private String getPreferenceSummary(AppPermissionGroup group) {
+ String groupSummary = getGroupSummary(group);
+
+ if (Utils.isModernPermissionGroup(group.getName()) && Utils.shouldShowPermissionUsage(
+ group.getName())) {
+ String lastAccessStr = Utils.getAbsoluteLastUsageString(getContext(),
+ PermissionUsages.loadLastGroupUsage(getContext(), group));
+ if (lastAccessStr != null) {
+ if (group.areRuntimePermissionsGranted()) {
+ return getContext().getString(R.string.app_permission_most_recent_summary,
+ lastAccessStr);
+ } else {
+ return getContext().getString(
+ R.string.app_permission_most_recent_denied_summary, lastAccessStr);
+ }
+ } else {
+ if (TextUtils.isEmpty(groupSummary) && Utils.isPermissionsHubEnabled()) {
+ if (group.areRuntimePermissionsGranted()) {
+ return getContext().getString(
+ R.string.app_permission_never_accessed_summary);
+ } else {
+ return getContext().getString(
+ R.string.app_permission_never_accessed_denied_summary);
+ }
+ }
+ }
+ }
+
+ return groupSummary;
+ }
+
+ private String getGroupSummary(AppPermissionGroup group) {
+ if (group.hasPermissionWithBackgroundMode() && group.areRuntimePermissionsGranted()) {
+ AppPermissionGroup backgroundGroup = group.getBackgroundPermissions();
+ if (backgroundGroup == null || !backgroundGroup.areRuntimePermissionsGranted()) {
+ return getContext().getString(R.string.permission_subtitle_only_in_foreground);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Class that shows additional permissions.
+ */
+ public static class AdditionalPermissionsFragment extends AutoSettingsFrameFragment {
+ AutoAppPermissionsFragment mOuterFragment;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ // Set this before calling super.onCreate as it is needed in onCreatePreferences
+ // (which is called from super.onCreate).
+ mOuterFragment = (AutoAppPermissionsFragment) getTargetFragment();
+ super.onCreate(savedInstanceState);
+ setHeaderLabel(mOuterFragment.getHeaderLabel());
+ }
+
+ @Override
+ public void onCreatePreferences(Bundle bundle, String s) {
+ setPreferenceScreen(mOuterFragment.mExtraScreen);
+ }
+ }
+}
+