1/*
2 * Copyright (C) 2016 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 */
16package com.android.carrierdefaultapp;
17
18import android.app.Notification;
19import android.app.NotificationChannel;
20import android.app.NotificationManager;
21import android.app.PendingIntent;
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.Intent;
25import android.content.pm.PackageManager;
26import android.content.res.Resources;
27import android.os.Bundle;
28import android.telephony.SubscriptionManager;
29import android.telephony.TelephonyManager;
30import android.text.TextUtils;
31import android.util.Log;
32import com.android.internal.telephony.PhoneConstants;
33import com.android.carrierdefaultapp.R;
34/**
35 * This util class provides common logic for carrier actions
36 */
37public class CarrierActionUtils {
38    private static final String TAG = CarrierActionUtils.class.getSimpleName();
39
40    private static final String PORTAL_NOTIFICATION_TAG = "CarrierDefault.Portal.Notification";
41    private static final String NO_DATA_NOTIFICATION_TAG = "CarrierDefault.NoData.Notification";
42    private static final String NOTIFICATION_CHANNEL_ID_MOBILE_DATA_STATUS = "mobile_data_status";
43    private static final int PORTAL_NOTIFICATION_ID = 0;
44    private static final int NO_DATA_NOTIFICATION_ID = 1;
45    private static boolean ENABLE = true;
46
47    // A list of supported carrier action idx
48    public static final int CARRIER_ACTION_ENABLE_METERED_APNS               = 0;
49    public static final int CARRIER_ACTION_DISABLE_METERED_APNS              = 1;
50    public static final int CARRIER_ACTION_DISABLE_RADIO                     = 2;
51    public static final int CARRIER_ACTION_ENABLE_RADIO                      = 3;
52    public static final int CARRIER_ACTION_SHOW_PORTAL_NOTIFICATION          = 4;
53    public static final int CARRIER_ACTION_SHOW_NO_DATA_SERVICE_NOTIFICATION = 5;
54    public static final int CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS          = 6;
55    public static final int CARRIER_ACTION_ENABLE_DEFAULT_URL_HANDLER        = 7;
56    public static final int CARRIER_ACTION_DISABLE_DEFAULT_URL_HANDLER       = 8;
57    public static final int CARRIER_ACTION_REGISTER_DEFAULT_NETWORK_AVAIL    = 9;
58    public static final int CARRIER_ACTION_DEREGISTER_DEFAULT_NETWORK_AVAIL  = 10;
59
60    public static void applyCarrierAction(int actionIdx, Intent intent, Context context) {
61        switch (actionIdx) {
62            case CARRIER_ACTION_ENABLE_METERED_APNS:
63                onEnableAllMeteredApns(intent, context);
64                break;
65            case CARRIER_ACTION_DISABLE_METERED_APNS:
66                onDisableAllMeteredApns(intent, context);
67                break;
68            case CARRIER_ACTION_DISABLE_RADIO:
69                onDisableRadio(intent, context);
70                break;
71            case CARRIER_ACTION_ENABLE_RADIO:
72                onEnableRadio(intent, context);
73                break;
74            case CARRIER_ACTION_SHOW_PORTAL_NOTIFICATION:
75                onShowCaptivePortalNotification(intent, context);
76                break;
77            case CARRIER_ACTION_SHOW_NO_DATA_SERVICE_NOTIFICATION:
78                onShowNoDataServiceNotification(context);
79                break;
80            case CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS:
81                onCancelAllNotifications(context);
82                break;
83            case CARRIER_ACTION_ENABLE_DEFAULT_URL_HANDLER:
84                onEnableDefaultURLHandler(context);
85                break;
86            case CARRIER_ACTION_DISABLE_DEFAULT_URL_HANDLER:
87                onDisableDefaultURLHandler(context);
88                break;
89            case CARRIER_ACTION_REGISTER_DEFAULT_NETWORK_AVAIL:
90                onRegisterDefaultNetworkAvail(intent, context);
91                break;
92            case CARRIER_ACTION_DEREGISTER_DEFAULT_NETWORK_AVAIL:
93                onDeregisterDefaultNetworkAvail(intent, context);
94                break;
95            default:
96                loge("unsupported carrier action index: " + actionIdx);
97        }
98    }
99
100    private static void onDisableAllMeteredApns(Intent intent, Context context) {
101        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
102                SubscriptionManager.getDefaultVoiceSubscriptionId());
103        logd("onDisableAllMeteredApns subId: " + subId);
104        final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
105        telephonyMgr.carrierActionSetMeteredApnsEnabled(subId, !ENABLE);
106    }
107
108    private static void onEnableAllMeteredApns(Intent intent, Context context) {
109        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
110                SubscriptionManager.getDefaultVoiceSubscriptionId());
111        logd("onEnableAllMeteredApns subId: " + subId);
112        final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
113        telephonyMgr.carrierActionSetMeteredApnsEnabled(subId, ENABLE);
114    }
115
116    private static void onEnableDefaultURLHandler(Context context) {
117        logd("onEnableDefaultURLHandler");
118        final PackageManager pm = context.getPackageManager();
119        pm.setComponentEnabledSetting(
120                new ComponentName(context, CaptivePortalLoginActivity.getAlias(context)),
121                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
122    }
123
124    private static void onDisableDefaultURLHandler(Context context) {
125        logd("onDisableDefaultURLHandler");
126        final PackageManager pm = context.getPackageManager();
127        pm.setComponentEnabledSetting(
128                new ComponentName(context, CaptivePortalLoginActivity.getAlias(context)),
129                PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
130    }
131
132    private static void onRegisterDefaultNetworkAvail(Intent intent, Context context) {
133        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
134                SubscriptionManager.getDefaultVoiceSubscriptionId());
135        logd("onRegisterDefaultNetworkAvail subId: " + subId);
136        final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
137        telephonyMgr.carrierActionReportDefaultNetworkStatus(subId, true);
138    }
139
140    private static void onDeregisterDefaultNetworkAvail(Intent intent, Context context) {
141        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
142                SubscriptionManager.getDefaultVoiceSubscriptionId());
143        logd("onDeregisterDefaultNetworkAvail subId: " + subId);
144        final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
145        telephonyMgr.carrierActionReportDefaultNetworkStatus(subId, false);
146    }
147
148    private static void onDisableRadio(Intent intent, Context context) {
149        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
150                SubscriptionManager.getDefaultVoiceSubscriptionId());
151        logd("onDisableRadio subId: " + subId);
152        final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
153        telephonyMgr.carrierActionSetRadioEnabled(subId, !ENABLE);
154    }
155
156    private static void onEnableRadio(Intent intent, Context context) {
157        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
158                SubscriptionManager.getDefaultVoiceSubscriptionId());
159        logd("onEnableRadio subId: " + subId);
160        final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
161        telephonyMgr.carrierActionSetRadioEnabled(subId, ENABLE);
162    }
163
164    private static void onShowCaptivePortalNotification(Intent intent, Context context) {
165        logd("onShowCaptivePortalNotification");
166        Intent portalIntent = new Intent(context, CaptivePortalLoginActivity.class);
167        portalIntent.putExtras(intent);
168        portalIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT
169                | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
170        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, portalIntent,
171                PendingIntent.FLAG_UPDATE_CURRENT);
172        Notification notification = getNotification(context, R.string.portal_notification_id,
173                R.string.portal_notification_detail, pendingIntent);
174        try {
175            context.getSystemService(NotificationManager.class)
176                    .notify(PORTAL_NOTIFICATION_TAG, PORTAL_NOTIFICATION_ID, notification);
177        } catch (NullPointerException npe) {
178            loge("setNotificationVisible: " + npe);
179        }
180    }
181
182    private static void onShowNoDataServiceNotification(Context context) {
183        logd("onShowNoDataServiceNotification");
184        Notification notification = getNotification(context, R.string.no_data_notification_id,
185                R.string.no_data_notification_detail, null);
186        try {
187            context.getSystemService(NotificationManager.class)
188                    .notify(NO_DATA_NOTIFICATION_TAG, NO_DATA_NOTIFICATION_ID, notification);
189        } catch (NullPointerException npe) {
190            loge("setNotificationVisible: " + npe);
191        }
192    }
193
194    private static void onCancelAllNotifications(Context context) {
195        logd("onCancelAllNotifications");
196        context.getSystemService(NotificationManager.class).cancelAll();
197    }
198
199    private static Notification getNotification(Context context, int titleId, int textId,
200                                         PendingIntent pendingIntent) {
201        final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
202        final Resources resources = context.getResources();
203        String spn = telephonyMgr.getSimOperatorName();
204        if (TextUtils.isEmpty(spn)) {
205            // There is no consistent way to get the current carrier name as MNOs didn't
206            // bother to set EF_SPN. in the long term, we should display a generic wording if
207            // spn from subscription is not set.
208            spn = telephonyMgr.getNetworkOperatorName();
209        }
210        final Bundle extras = Bundle.forPair(Notification.EXTRA_SUBSTITUTE_APP_NAME,
211                resources.getString(R.string.android_system_label));
212        createNotificationChannels(context);
213        Notification.Builder builder = new Notification.Builder(context)
214                .setContentTitle(resources.getString(titleId))
215                .setContentText(String.format(resources.getString(textId), spn))
216                .setSmallIcon(R.drawable.ic_sim_card)
217                .setColor(context.getColor(
218                        com.android.internal.R.color.system_notification_accent_color))
219                .setOngoing(true)
220                .setPriority(Notification.PRIORITY_HIGH)
221                .setDefaults(Notification.DEFAULT_ALL)
222                .setVisibility(Notification.VISIBILITY_PUBLIC)
223                .setLocalOnly(true)
224                .setWhen(System.currentTimeMillis())
225                .setShowWhen(false)
226                .setExtras(extras)
227                .setChannel(NOTIFICATION_CHANNEL_ID_MOBILE_DATA_STATUS);
228
229        if (pendingIntent != null) {
230            builder.setContentIntent(pendingIntent);
231        }
232        return builder.build();
233    }
234
235    /**
236     * Creates the notification channel and registers it with NotificationManager. Also used to
237     * update an existing channel's name.
238     */
239    static void createNotificationChannels(Context context) {
240        context.getSystemService(NotificationManager.class)
241                .createNotificationChannel(new NotificationChannel(
242                NOTIFICATION_CHANNEL_ID_MOBILE_DATA_STATUS,
243                context.getResources().getString(
244                        R.string.mobile_data_status_notification_channel_name),
245                NotificationManager.IMPORTANCE_DEFAULT));
246    }
247
248    private static void logd(String s) {
249        Log.d(TAG, s);
250    }
251
252    private static void loge(String s) {
253        Log.e(TAG, s);
254    }
255}
256