1 /*
2  * Copyright (C) 2022 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.appinfo;
18 
19 import android.app.Activity;
20 import android.content.ActivityNotFoundException;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.PackageManager;
25 import android.content.pm.ResolveInfo;
26 import android.content.res.Resources;
27 import android.location.LocationManager;
28 import android.os.Bundle;
29 import android.util.Log;
30 
31 import androidx.annotation.Nullable;
32 import androidx.annotation.VisibleForTesting;
33 import androidx.preference.Preference;
34 import androidx.preference.PreferenceScreen;
35 
36 import java.util.Objects;
37 
38 /**
39  * Preference Controller for the "All Services" preference in the "App Info" page.
40  */
41 public class AppAllServicesPreferenceController extends AppInfoPreferenceControllerBase {
42 
43     private static final String TAG = "AllServicesPrefControl";
44     private static final String SUMMARY_METADATA_KEY = "app_features_preference_summary";
45 
46     private final PackageManager mPackageManager;
47 
48     private String mPackageName;
49 
AppAllServicesPreferenceController(Context context, String preferenceKey)50     public AppAllServicesPreferenceController(Context context,
51             String preferenceKey) {
52         super(context, preferenceKey);
53         mPackageManager = context.getPackageManager();
54     }
55 
56     @Override
displayPreference(PreferenceScreen screen)57     public void displayPreference(PreferenceScreen screen) {
58         super.displayPreference(screen);
59         CharSequence summary = getStorageSummary();
60         if (summary != null) {
61             mPreference.setSummary(summary);
62         }
63     }
64 
65     @Nullable
getStorageSummary()66     private CharSequence getStorageSummary() {
67         ResolveInfo resolveInfo = getResolveInfo(PackageManager.GET_META_DATA);
68         if (resolveInfo == null) {
69             Log.d(TAG, "mResolveInfo is null.");
70             return null;
71         }
72         final Bundle metaData = resolveInfo.activityInfo.metaData;
73         if (metaData != null) {
74             try {
75                 final Resources pkgRes = mPackageManager.getResourcesForActivity(
76                         new ComponentName(mPackageName, resolveInfo.activityInfo.name));
77                 return pkgRes.getString(metaData.getInt(SUMMARY_METADATA_KEY));
78             } catch (Resources.NotFoundException exception) {
79                 Log.d(TAG, "Resource not found for summary string.");
80             } catch (PackageManager.NameNotFoundException exception) {
81                 Log.d(TAG, "Name of resource not found for summary string.");
82             }
83         }
84         return null;
85     }
86 
87     @Override
getAvailabilityStatus()88     public int getAvailabilityStatus() {
89         if (canPackageHandleIntent() && isLocationProvider()) {
90             return AVAILABLE;
91         }
92         return CONDITIONALLY_UNAVAILABLE;
93     }
94 
95     @VisibleForTesting
isLocationProvider()96     boolean isLocationProvider() {
97         return Objects.requireNonNull(
98                 mContext.getSystemService(LocationManager.class)).isProviderPackage(mPackageName);
99     }
100 
101     @VisibleForTesting
canPackageHandleIntent()102     boolean canPackageHandleIntent() {
103         return getResolveInfo(0) != null;
104     }
105 
106     @Override
handlePreferenceTreeClick(Preference preference)107     public boolean handlePreferenceTreeClick(Preference preference) {
108         if (getPreferenceKey().equals(preference.getKey())) {
109             startAllServicesActivity();
110             return true;
111         }
112         return false;
113     }
114 
115     /**
116      * Set the package name of the package for which the "All Services" activity needs to be shown.
117      *
118      * @param packageName Name of the package for which the services need to be shown.
119      */
setPackageName(String packageName)120     public void setPackageName(String packageName) {
121         mPackageName = packageName;
122     }
123 
startAllServicesActivity()124     private void startAllServicesActivity() {
125         final Intent featuresIntent = new Intent(Intent.ACTION_VIEW_APP_FEATURES);
126         // This won't be null since the preference is only shown for packages that can handle the
127         // intent.
128         ResolveInfo resolveInfo = getResolveInfo(0);
129         featuresIntent.setComponent(
130                 new ComponentName(mPackageName, resolveInfo.activityInfo.name));
131 
132         Activity activity = mParent.getActivity();
133         try {
134             if (activity != null) {
135                 activity.startActivity(featuresIntent);
136             }
137         } catch (ActivityNotFoundException e) {
138             Log.e(TAG, "The app cannot handle android.intent.action.VIEW_APP_FEATURES");
139         }
140     }
141 
142     @Nullable
getResolveInfo(int flags)143     private ResolveInfo getResolveInfo(int flags) {
144         if (mPackageName == null) {
145             return null;
146         }
147         final Intent featuresIntent = new Intent(Intent.ACTION_VIEW_APP_FEATURES);
148         featuresIntent.setPackage(mPackageName);
149 
150         return mPackageManager.resolveActivity(featuresIntent, flags);
151     }
152 }
153