1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.applications; 18 19 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 20 21 import android.app.Activity; 22 import android.app.Dialog; 23 import android.app.admin.DevicePolicyManager; 24 import android.app.settings.SettingsEnums; 25 import android.content.BroadcastReceiver; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.content.pm.PackageInfo; 30 import android.content.pm.PackageManager; 31 import android.content.pm.PackageManager.NameNotFoundException; 32 import android.hardware.usb.IUsbManager; 33 import android.os.Bundle; 34 import android.os.IBinder; 35 import android.os.ServiceManager; 36 import android.os.UserHandle; 37 import android.os.UserManager; 38 import android.text.TextUtils; 39 import android.util.Log; 40 41 import androidx.appcompat.app.AlertDialog; 42 import androidx.fragment.app.DialogFragment; 43 import androidx.fragment.app.Fragment; 44 45 import com.android.settings.SettingsActivity; 46 import com.android.settings.SettingsPreferenceFragment; 47 import com.android.settings.applications.manageapplications.ManageApplications; 48 import com.android.settings.core.SubSettingLauncher; 49 import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 50 import com.android.settings.overlay.FeatureFactory; 51 import com.android.settingslib.RestrictedLockUtilsInternal; 52 import com.android.settingslib.applications.ApplicationsState; 53 import com.android.settingslib.applications.ApplicationsState.AppEntry; 54 55 import java.util.ArrayList; 56 57 public abstract class AppInfoBase extends SettingsPreferenceFragment 58 implements ApplicationsState.Callbacks { 59 60 public static final String ARG_PACKAGE_NAME = "package"; 61 public static final String ARG_PACKAGE_UID = "uid"; 62 63 private static final String TAG = "AppInfoBase"; 64 65 protected EnforcedAdmin mAppsControlDisallowedAdmin; 66 protected boolean mAppsControlDisallowedBySystem; 67 68 protected ApplicationFeatureProvider mApplicationFeatureProvider; 69 protected ApplicationsState mState; 70 protected ApplicationsState.Session mSession; 71 protected ApplicationsState.AppEntry mAppEntry; 72 protected PackageInfo mPackageInfo; 73 protected int mUserId; 74 protected String mPackageName; 75 76 protected IUsbManager mUsbManager; 77 protected DevicePolicyManager mDpm; 78 protected UserManager mUserManager; 79 protected PackageManager mPm; 80 81 // Dialog identifiers used in showDialog 82 protected static final int DLG_BASE = 0; 83 84 protected boolean mFinishing; 85 protected boolean mListeningToPackageRemove; 86 87 @Override onCreate(Bundle savedInstanceState)88 public void onCreate(Bundle savedInstanceState) { 89 super.onCreate(savedInstanceState); 90 mFinishing = false; 91 final Activity activity = getActivity(); 92 mApplicationFeatureProvider = FeatureFactory.getFactory(activity) 93 .getApplicationFeatureProvider(activity); 94 mState = ApplicationsState.getInstance(activity.getApplication()); 95 mSession = mState.newSession(this, getSettingsLifecycle()); 96 mDpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); 97 mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE); 98 mPm = activity.getPackageManager(); 99 IBinder b = ServiceManager.getService(Context.USB_SERVICE); 100 mUsbManager = IUsbManager.Stub.asInterface(b); 101 102 retrieveAppEntry(); 103 startListeningToPackageRemove(); 104 } 105 106 @Override onResume()107 public void onResume() { 108 super.onResume(); 109 mAppsControlDisallowedAdmin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced( 110 getActivity(), UserManager.DISALLOW_APPS_CONTROL, mUserId); 111 mAppsControlDisallowedBySystem = RestrictedLockUtilsInternal.hasBaseUserRestriction( 112 getActivity(), UserManager.DISALLOW_APPS_CONTROL, mUserId); 113 114 if (!refreshUi()) { 115 setIntentAndFinish(true /* appChanged */); 116 } 117 } 118 119 120 @Override onDestroy()121 public void onDestroy() { 122 stopListeningToPackageRemove(); 123 super.onDestroy(); 124 } 125 retrieveAppEntry()126 protected String retrieveAppEntry() { 127 final Bundle args = getArguments(); 128 mPackageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null; 129 Intent intent = (args == null) ? 130 getIntent() : (Intent) args.getParcelable("intent"); 131 if (mPackageName == null) { 132 if (intent != null && intent.getData() != null) { 133 mPackageName = intent.getData().getSchemeSpecificPart(); 134 } 135 } 136 if (intent != null && intent.hasExtra(Intent.EXTRA_USER_HANDLE)) { 137 mUserId = ((UserHandle) intent.getParcelableExtra( 138 Intent.EXTRA_USER_HANDLE)).getIdentifier(); 139 } else { 140 mUserId = UserHandle.myUserId(); 141 } 142 mAppEntry = mState.getEntry(mPackageName, mUserId); 143 if (mAppEntry != null) { 144 // Get application info again to refresh changed properties of application 145 try { 146 mPackageInfo = mPm.getPackageInfoAsUser(mAppEntry.info.packageName, 147 PackageManager.MATCH_DISABLED_COMPONENTS | 148 PackageManager.GET_SIGNING_CERTIFICATES | 149 PackageManager.GET_PERMISSIONS, mUserId); 150 } catch (NameNotFoundException e) { 151 Log.e(TAG, "Exception when retrieving package:" + mAppEntry.info.packageName, e); 152 } 153 } else { 154 Log.w(TAG, "Missing AppEntry; maybe reinstalling?"); 155 mPackageInfo = null; 156 } 157 158 return mPackageName; 159 } 160 setIntentAndFinish(boolean appChanged)161 protected void setIntentAndFinish(boolean appChanged) { 162 Log.i(TAG, "appChanged=" + appChanged); 163 Intent intent = new Intent(); 164 intent.putExtra(ManageApplications.APP_CHG, appChanged); 165 SettingsActivity sa = (SettingsActivity) getActivity(); 166 sa.finishPreferencePanel(Activity.RESULT_OK, intent); 167 mFinishing = true; 168 } 169 showDialogInner(int id, int moveErrorCode)170 protected void showDialogInner(int id, int moveErrorCode) { 171 DialogFragment newFragment = MyAlertDialogFragment.newInstance(id, moveErrorCode); 172 newFragment.setTargetFragment(this, 0); 173 newFragment.show(getFragmentManager(), "dialog " + id); 174 } 175 refreshUi()176 protected abstract boolean refreshUi(); 177 createDialog(int id, int errorCode)178 protected abstract AlertDialog createDialog(int id, int errorCode); 179 180 @Override onRunningStateChanged(boolean running)181 public void onRunningStateChanged(boolean running) { 182 // No op. 183 } 184 185 @Override onRebuildComplete(ArrayList<AppEntry> apps)186 public void onRebuildComplete(ArrayList<AppEntry> apps) { 187 // No op. 188 } 189 190 @Override onPackageIconChanged()191 public void onPackageIconChanged() { 192 // No op. 193 } 194 195 @Override onPackageSizeChanged(String packageName)196 public void onPackageSizeChanged(String packageName) { 197 // No op. 198 } 199 200 @Override onAllSizesComputed()201 public void onAllSizesComputed() { 202 // No op. 203 } 204 205 @Override onLauncherInfoChanged()206 public void onLauncherInfoChanged() { 207 // No op. 208 } 209 210 @Override onLoadEntriesCompleted()211 public void onLoadEntriesCompleted() { 212 // No op. 213 } 214 215 @Override onPackageListChanged()216 public void onPackageListChanged() { 217 if (!refreshUi()) { 218 setIntentAndFinish(true /* appChanged */); 219 } 220 } 221 startAppInfoFragment(Class<?> fragment, int titleRes, String pkg, int uid, Fragment source, int request, int sourceMetricsCategory)222 public static void startAppInfoFragment(Class<?> fragment, int titleRes, 223 String pkg, int uid, Fragment source, int request, int sourceMetricsCategory) { 224 final Bundle args = new Bundle(); 225 args.putString(AppInfoBase.ARG_PACKAGE_NAME, pkg); 226 args.putInt(AppInfoBase.ARG_PACKAGE_UID, uid); 227 228 new SubSettingLauncher(source.getContext()) 229 .setDestination(fragment.getName()) 230 .setSourceMetricsCategory(sourceMetricsCategory) 231 .setTitleRes(titleRes) 232 .setArguments(args) 233 .setUserHandle(new UserHandle(UserHandle.getUserId(uid))) 234 .setResultListener(source, request) 235 .launch(); 236 } 237 238 public static class MyAlertDialogFragment extends InstrumentedDialogFragment { 239 240 private static final String ARG_ID = "id"; 241 242 @Override getMetricsCategory()243 public int getMetricsCategory() { 244 return SettingsEnums.DIALOG_APP_INFO_ACTION; 245 } 246 247 @Override onCreateDialog(Bundle savedInstanceState)248 public Dialog onCreateDialog(Bundle savedInstanceState) { 249 int id = getArguments().getInt(ARG_ID); 250 int errorCode = getArguments().getInt("moveError"); 251 Dialog dialog = ((AppInfoBase) getTargetFragment()).createDialog(id, errorCode); 252 if (dialog == null) { 253 throw new IllegalArgumentException("unknown id " + id); 254 } 255 return dialog; 256 } 257 newInstance(int id, int errorCode)258 public static MyAlertDialogFragment newInstance(int id, int errorCode) { 259 MyAlertDialogFragment dialogFragment = new MyAlertDialogFragment(); 260 Bundle args = new Bundle(); 261 args.putInt(ARG_ID, id); 262 args.putInt("moveError", errorCode); 263 dialogFragment.setArguments(args); 264 return dialogFragment; 265 } 266 } 267 startListeningToPackageRemove()268 protected void startListeningToPackageRemove() { 269 if (mListeningToPackageRemove) { 270 return; 271 } 272 mListeningToPackageRemove = true; 273 final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED); 274 filter.addDataScheme("package"); 275 getContext().registerReceiver(mPackageRemovedReceiver, filter); 276 } 277 stopListeningToPackageRemove()278 protected void stopListeningToPackageRemove() { 279 if (!mListeningToPackageRemove) { 280 return; 281 } 282 mListeningToPackageRemove = false; 283 getContext().unregisterReceiver(mPackageRemovedReceiver); 284 } 285 onPackageRemoved()286 protected void onPackageRemoved() { 287 getActivity().finishAndRemoveTask(); 288 } 289 290 protected final BroadcastReceiver mPackageRemovedReceiver = new BroadcastReceiver() { 291 @Override 292 public void onReceive(Context context, Intent intent) { 293 String packageName = intent.getData().getSchemeSpecificPart(); 294 if (!mFinishing && (mAppEntry == null || mAppEntry.info == null 295 || TextUtils.equals(mAppEntry.info.packageName, packageName))) { 296 onPackageRemoved(); 297 } 298 } 299 }; 300 301 } 302