1 /*
2  * Copyright (C) 2018 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.internal.telephony.uicc;
18 
19 import static android.content.Context.ALARM_SERVICE;
20 
21 import android.app.AlarmManager;
22 import android.app.Notification;
23 import android.app.NotificationManager;
24 import android.app.PendingIntent;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.content.res.Resources;
29 import android.net.Uri;
30 import android.os.SystemClock;
31 import android.provider.Settings;
32 import android.service.notification.StatusBarNotification;
33 import android.text.TextUtils;
34 
35 import com.android.internal.R;
36 import com.android.internal.annotations.VisibleForTesting;
37 import com.android.internal.telephony.util.NotificationChannelController;
38 
39 import java.util.Arrays;
40 import java.util.List;
41 
42 /**
43  * Utility methods for installing the carrier app when a SIM is insterted without the carrier app
44  * for that SIM installed.
45  */
46 @VisibleForTesting
47 public class InstallCarrierAppUtils {
48     // TODO(b/72714040) centralize notification IDs
49     private static final int ACTIVATE_CELL_SERVICE_NOTIFICATION_ID = 12;
50     private static CarrierAppInstallReceiver sCarrierAppInstallReceiver = null;
51 
showNotification(Context context, String pkgName)52     static void showNotification(Context context, String pkgName) {
53         Resources res = Resources.getSystem();
54         String title = res.getString(
55                 com.android.internal.R.string.install_carrier_app_notification_title);
56         String appName = getAppNameFromPackageName(context, pkgName);
57         String message;
58         if (TextUtils.isEmpty(appName)) {
59             message = res.getString(R.string.install_carrier_app_notification_text);
60         } else {
61             message = res.getString(R.string.install_carrier_app_notification_text_app_name,
62                     appName);
63         }
64         String downloadButtonText = res.getString(R.string.install_carrier_app_notification_button);
65 
66         boolean persistent = Settings.Global.getInt(
67                 context.getContentResolver(),
68                 Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT, 1) == 1;
69 
70         PendingIntent goToStore = PendingIntent.getActivity(context, 0,
71                 getPlayStoreIntent(pkgName), PendingIntent.FLAG_UPDATE_CURRENT);
72 
73         Notification.Action goToStoreAction =
74                 new Notification.Action.Builder(null, downloadButtonText, goToStore).build();
75 
76         Notification notification = new Notification.Builder(context,
77                 NotificationChannelController.CHANNEL_ID_SIM)
78                 .setContentTitle(title)
79                 .setContentText(message)
80                 .setSmallIcon(R.drawable.ic_signal_cellular_alt_24px)
81                 .addAction(goToStoreAction)
82                 .setOngoing(persistent)
83                 .setVisibility(Notification.VISIBILITY_SECRET) // Should not appear on lock screen
84                 .build();
85 
86         getNotificationManager(context).notify(
87                 pkgName,
88                 ACTIVATE_CELL_SERVICE_NOTIFICATION_ID,
89                 notification);
90     }
91 
hideAllNotifications(Context context)92     static void hideAllNotifications(Context context) {
93         NotificationManager notificationManager = getNotificationManager(context);
94         StatusBarNotification[] activeNotifications = notificationManager.getActiveNotifications();
95 
96         if (activeNotifications == null) {
97             return;
98         }
99 
100         for (StatusBarNotification notification : activeNotifications) {
101             if (notification.getId() == ACTIVATE_CELL_SERVICE_NOTIFICATION_ID) {
102                 notificationManager.cancel(notification.getTag(), notification.getId());
103             }
104         }
105     }
106 
hideNotification(Context context, String pkgName)107     static void hideNotification(Context context, String pkgName) {
108         getNotificationManager(context).cancel(pkgName, ACTIVATE_CELL_SERVICE_NOTIFICATION_ID);
109     }
110 
getPlayStoreIntent(String pkgName)111     static Intent getPlayStoreIntent(String pkgName) {
112         // Open play store to download package
113         Intent storeIntent = new Intent(Intent.ACTION_VIEW);
114         storeIntent.setData(Uri.parse("market://details?id=" + pkgName));
115         storeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
116 
117         return storeIntent;
118     }
119 
showNotificationIfNotInstalledDelayed(Context context, String pkgName, long delayMillis)120     static void showNotificationIfNotInstalledDelayed(Context context,
121             String pkgName, long delayMillis) {
122         AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
123         PendingIntent pendingIntent = PendingIntent.getBroadcast(
124                 context,
125                 0,
126                 ShowInstallAppNotificationReceiver.get(context, pkgName),
127                 0);
128         alarmManager.set(AlarmManager.ELAPSED_REALTIME,
129                 SystemClock.elapsedRealtime() + delayMillis,
130                 pendingIntent);
131 
132     }
133 
registerPackageInstallReceiver(Context context)134     static void registerPackageInstallReceiver(Context context) {
135         if (sCarrierAppInstallReceiver == null) {
136             sCarrierAppInstallReceiver = new CarrierAppInstallReceiver();
137             context = context.getApplicationContext();
138             IntentFilter intentFilter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
139             intentFilter.addDataScheme("package");
140             context.registerReceiver(sCarrierAppInstallReceiver, intentFilter);
141         }
142     }
143 
unregisterPackageInstallReceiver(Context context)144     static void unregisterPackageInstallReceiver(Context context) {
145         if (sCarrierAppInstallReceiver == null) {
146             return;
147         }
148         context = context.getApplicationContext();
149         context.unregisterReceiver(sCarrierAppInstallReceiver);
150         sCarrierAppInstallReceiver = null;
151     }
152 
isPackageInstallNotificationActive(Context context)153     static boolean isPackageInstallNotificationActive(Context context) {
154         StatusBarNotification[] activeNotifications =
155                 getNotificationManager(context).getActiveNotifications();
156 
157         for (StatusBarNotification notification : activeNotifications) {
158             if (notification.getId() == ACTIVATE_CELL_SERVICE_NOTIFICATION_ID) {
159                 return true;
160             }
161         }
162         return false;
163     }
164 
getAppNameFromPackageName(Context context, String packageName)165     static String getAppNameFromPackageName(Context context, String packageName) {
166         String whitelistSetting = Settings.Global.getString(
167                 context.getContentResolver(),
168                 Settings.Global.CARRIER_APP_NAMES);
169         return getAppNameFromPackageName(packageName, whitelistSetting);
170     }
171 
172     /**
173      * @param packageName the name of the package.  Will be used as a key into the map
174      * @param mapString map of package name to application name in the format:
175      *                  packageName1:appName1;packageName2:appName2;
176      * @return the name of the application for the package name provided.
177      */
178     @VisibleForTesting
getAppNameFromPackageName(String packageName, String mapString)179     public static String getAppNameFromPackageName(String packageName, String mapString) {
180         packageName = packageName.toLowerCase();
181         final String pairDelim = "\\s*;\\s*";
182         final String keyValueDelim = "\\s*:\\s*";
183 
184         if (TextUtils.isEmpty(mapString)) {
185             return null;
186         }
187 
188         List<String> keyValuePairList = Arrays.asList(mapString.split(pairDelim));
189 
190         if (keyValuePairList.isEmpty()) {
191             return null;
192         }
193 
194         for (String keyValueString: keyValuePairList) {
195             String[] keyValue = keyValueString.split(keyValueDelim);
196 
197             if (keyValue.length == 2) {
198                 if (keyValue[0].equals(packageName)) {
199                     return keyValue[1];
200                 }
201             }
202         }
203         return null;
204     }
getNotificationManager(Context context)205     private static NotificationManager getNotificationManager(Context context) {
206         return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
207     }
208 }
209