diff options
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); + } + } +} + |