/* * 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.permissioncontroller.permission.ui.handheld; import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID; import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID; import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED; import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__ALLOWED; import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__ALLOWED_FOREGROUND; import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__DENIED; import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__UNDEFINED; import static com.android.permissioncontroller.permission.ui.Category.ALLOWED; import static com.android.permissioncontroller.permission.ui.Category.ALLOWED_FOREGROUND; import static com.android.permissioncontroller.permission.ui.Category.ASK; import static com.android.permissioncontroller.permission.ui.Category.DENIED; import static com.android.permissioncontroller.permission.ui.handheld.UtilsKt.pressBack; import android.Manifest; import android.app.ActionBar; import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import androidx.annotation.NonNull; import androidx.lifecycle.ViewModelProvider; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import com.android.permissioncontroller.PermissionControllerStatsLog; import com.android.permissioncontroller.R; import com.android.permissioncontroller.permission.ui.Category; import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel; import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModelFactory; import com.android.permissioncontroller.permission.utils.KotlinUtils; import com.android.permissioncontroller.permission.utils.Utils; import com.android.settingslib.HelpUtils; import com.android.settingslib.utils.applications.AppUtils; import java.text.Collator; import java.util.List; import java.util.Map; import java.util.Random; import kotlin.Pair; /** * Show and manage apps which request a single permission group. * *
Shows a list of apps which request at least on permission of this group.
*/
public final class PermissionAppsFragment extends SettingsWithLargeHeader {
private static final String KEY_SHOW_SYSTEM_PREFS = "_showSystem";
private static final String CREATION_LOGGED_SYSTEM_PREFS = "_creationLogged";
private static final String KEY_FOOTER = "_footer";
private static final String KEY_EMPTY = "_empty";
private static final String LOG_TAG = "PermissionAppsFragment";
private static final String STORAGE_ALLOWED_FULL = "allowed_storage_full";
private static final String STORAGE_ALLOWED_SCOPED = "allowed_storage_scoped";
private static final int SHOW_LOAD_DELAY_MS = 200;
/**
* Create a bundle with the arguments needed by this fragment
*
* @param permGroupName The name of the permission group
* @param sessionId The current session ID
* @return A bundle with all of the args placed
*/
public static Bundle createArgs(String permGroupName, long sessionId) {
Bundle arguments = new Bundle();
arguments.putString(Intent.EXTRA_PERMISSION_GROUP_NAME, permGroupName);
arguments.putLong(EXTRA_SESSION_ID, sessionId);
return arguments;
}
private MenuItem mShowSystemMenu;
private MenuItem mHideSystemMenu;
private String mPermGroupName;
private Collator mCollator;
private PermissionAppsViewModel mViewModel;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPermGroupName = getArguments().getString(Intent.EXTRA_PERMISSION_GROUP_NAME);
if (mPermGroupName == null) {
mPermGroupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME);
}
mCollator = Collator.getInstance(
getContext().getResources().getConfiguration().getLocales().get(0));
PermissionAppsViewModelFactory factory =
new PermissionAppsViewModelFactory(getActivity().getApplication(), mPermGroupName,
this, new Bundle());
mViewModel = new ViewModelProvider(this, factory).get(PermissionAppsViewModel.class);
mViewModel.getCategorizedAppsLiveData().observe(this, this::onPackagesLoaded);
mViewModel.getShouldShowSystemLiveData().observe(this, this::updateMenu);
mViewModel.getHasSystemAppsLiveData().observe(this, (Boolean hasSystem) ->
getActivity().invalidateOptionsMenu());
if (!mViewModel.arePackagesLoaded()) {
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(() -> {
if (!mViewModel.arePackagesLoaded()) {
setLoading(true /* loading */, false /* animate */);
}
}, SHOW_LOAD_DELAY_MS);
}
setHasOptionsMenu(true);
final ActionBar ab = getActivity().getActionBar();
if (ab != null) {
ab.setDisplayHomeAsUpEnabled(true);
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
if (mViewModel.getHasSystemAppsLiveData().getValue()) {
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(mViewModel.getShouldShowSystemLiveData().getValue());
}
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:
mViewModel.updateShowSystem(false);
pressBack(this);
return true;
case MENU_SHOW_SYSTEM:
case MENU_HIDE_SYSTEM:
mViewModel.updateShowSystem(item.getItemId() == MENU_SHOW_SYSTEM);
break;
}
return super.onOptionsItemSelected(item);
}
private void updateMenu(Boolean showSystem) {
if (showSystem == null) {
showSystem = false;
}
if (mShowSystemMenu != null && mHideSystemMenu != null) {
mShowSystemMenu.setVisible(!showSystem);
mHideSystemMenu.setVisible(showSystem);
}
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
bindUi(this, mPermGroupName);
}
private static void bindUi(SettingsWithLargeHeader fragment, @NonNull String groupName) {
Context context = fragment.getContext();
if (context == null || fragment.getActivity() == null) {
return;
}
Drawable icon = KotlinUtils.INSTANCE.getPermGroupIcon(context, groupName);
CharSequence label = KotlinUtils.INSTANCE.getPermGroupLabel(context, groupName);
CharSequence description = KotlinUtils.INSTANCE.getPermGroupDescription(context, groupName);
fragment.setHeader(icon, label, null, null, true);
fragment.setSummary(Utils.getPermissionGroupDescriptionString(fragment.getActivity(),
groupName, description), null);
fragment.getActivity().setTitle(label);
}
private void onPackagesLoaded(Map