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