1 /*
2  * Copyright (C) 2021 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.emergency;
18 
19 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
20 import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
21 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
22 
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.ApplicationInfo;
26 import android.content.pm.PackageManager;
27 import android.content.pm.ResolveInfo;
28 import android.graphics.Bitmap;
29 import android.graphics.Canvas;
30 import android.graphics.drawable.BitmapDrawable;
31 import android.graphics.drawable.Drawable;
32 import android.os.Bundle;
33 import android.text.TextUtils;
34 import android.util.DisplayMetrics;
35 import android.util.Log;
36 import android.util.TypedValue;
37 import android.view.View;
38 import android.widget.Button;
39 
40 import androidx.annotation.VisibleForTesting;
41 import androidx.preference.PreferenceScreen;
42 
43 import com.android.settings.R;
44 import com.android.settings.Utils;
45 import com.android.settings.core.BasePreferenceController;
46 import com.android.settings.overlay.FeatureFactory;
47 import com.android.settingslib.widget.LayoutPreference;
48 
49 import java.util.List;
50 
51 /**
52  * Preference controller for More settings button
53  */
54 public class MoreSettingsPreferenceController extends BasePreferenceController implements
55         View.OnClickListener {
56 
57     private static final String EXTRA_KEY_ATTRIBUTION = "attribution";
58     private static final String TAG = "MoreSettingsPrefCtrl";
59     @VisibleForTesting
60     Intent mIntent;
61     private LayoutPreference mPreference;
62 
MoreSettingsPreferenceController(Context context, String preferenceKey)63     public MoreSettingsPreferenceController(Context context, String preferenceKey) {
64         super(context, preferenceKey);
65         final String packageName = mContext.getResources().getString(
66                 R.string.config_emergency_package_name);
67 
68         if (TextUtils.isEmpty(packageName)) {
69             return;
70         }
71         mIntent = new Intent(Intent.ACTION_MAIN)
72                 .setPackage(packageName);
73 
74         final List<ResolveInfo> info = mContext.getPackageManager()
75                 .queryIntentActivities(mIntent, MATCH_SYSTEM_ONLY);
76 
77         if (info != null && !info.isEmpty()) {
78             mIntent.setClassName(packageName, info.get(0).activityInfo.name);
79         } else {
80             mIntent = null;
81         }
82     }
83 
84     @Override
displayPreference(PreferenceScreen screen)85     public void displayPreference(PreferenceScreen screen) {
86         super.displayPreference(screen);
87         mPreference = screen.findPreference(getPreferenceKey());
88         final Button button = mPreference.findViewById(R.id.button);
89         final Drawable icon = getIcon();
90         button.setText(getButtonText());
91         if (icon != null) {
92             button.setCompoundDrawablesWithIntrinsicBounds(
93                     /* left= */ icon,
94                     /* top= */null,
95                     /* right= */ null,
96                     /* bottom= */ null);
97             button.setVisibility(View.VISIBLE);
98         }
99 
100         button.setOnClickListener(this);
101     }
102 
103     @Override
getAvailabilityStatus()104     public int getAvailabilityStatus() {
105         if (mIntent == null) {
106             return UNSUPPORTED_ON_DEVICE;
107         } else {
108             return AVAILABLE;
109         }
110     }
111 
112     @Override
onClick(View v)113     public void onClick(View v) {
114         FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
115                 .logClickedPreference(mPreference, getMetricsCategory());
116         final Intent intent = new Intent(mIntent)
117                 .addCategory(Intent.CATEGORY_LAUNCHER)
118                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
119         Bundle bundle = new Bundle();
120         bundle.putString(EXTRA_KEY_ATTRIBUTION, mContext.getPackageName());
121         mContext.startActivity(intent, bundle);
122     }
123 
getIcon()124     private Drawable getIcon() {
125         final String packageName = mContext.getResources().getString(
126                 R.string.config_emergency_package_name);
127         try {
128             final PackageManager pm = mContext.getPackageManager();
129             final ApplicationInfo appInfo = pm.getApplicationInfo(
130                     packageName, MATCH_DISABLED_COMPONENTS
131                             | MATCH_DISABLED_UNTIL_USED_COMPONENTS);
132             return getScaledDrawable(mContext, Utils.getBadgedIcon(mContext, appInfo), 24, 24);
133         } catch (Exception e) {
134             Log.d(TAG, "Failed to get open app button icon", e);
135             return null;
136         }
137     }
138 
getButtonText()139     private CharSequence getButtonText() {
140         final String packageName = mContext.getResources().getString(
141                 R.string.config_emergency_package_name);
142         try {
143             final PackageManager pm = mContext.getPackageManager();
144             final ApplicationInfo appInfo = pm.getApplicationInfo(
145                     packageName, MATCH_DISABLED_COMPONENTS
146                             | MATCH_DISABLED_UNTIL_USED_COMPONENTS);
147             return mContext.getString(R.string.open_app_button, appInfo.loadLabel(pm));
148         } catch (Exception e) {
149             Log.d(TAG, "Failed to get open app button text, falling back.");
150             return "";
151         }
152     }
153 
getScaledDrawable(Context context, Drawable icon, int width, int height)154     private static Drawable getScaledDrawable(Context context, Drawable icon, int width,
155             int height) {
156         DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
157         int widthInDp =
158                 (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, width, displayMetrics);
159         int heightInDp =
160                 (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, height,
161                         displayMetrics);
162 
163         return new BitmapDrawable(context.getResources(),
164                 convertToBitmap(icon, widthInDp, heightInDp));
165     }
166 
convertToBitmap(Drawable icon, int width, int height)167     private static Bitmap convertToBitmap(Drawable icon, int width, int height) {
168         if (icon == null) {
169             return null;
170         }
171         Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
172         Canvas canvas = new Canvas(bitmap);
173         icon.setBounds(0, 0, width, height);
174         icon.draw(canvas);
175         return bitmap;
176     }
177 }
178