1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/*
2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project
3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License");
5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License.
6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at
7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *      http://www.apache.org/licenses/LICENSE-2.0
9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software
11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS,
12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and
14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License.
15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.receiver;
18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.app.Notification;
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.app.PendingIntent;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.BroadcastReceiver;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ComponentName;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ContentValues;
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Intent;
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.pm.PackageManager;
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.res.Resources;
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.Telephony;
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.Telephony.Sms;
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.support.v4.app.NotificationCompat;
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.support.v4.app.NotificationCompat.Builder;
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.support.v4.app.NotificationCompat.Style;
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.support.v4.app.NotificationManagerCompat;
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.ArrayList;
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.regex.Pattern;
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.regex.PatternSyntaxException;
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.Factory;
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.R;
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.BugleNotifications;
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.MessageNotificationState;
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.NoConfirmationSmsSendService;
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.action.ReceiveSmsMessageAction;
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.sms.MmsUtils;
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.UIIntents;
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.BugleGservices;
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.BugleGservicesKeys;
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.DebugUtils;
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.LogUtil;
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.OsUtil;
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.PendingIntentConstants;
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.PhoneUtils;
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/**
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Class that receives incoming SMS messages through android.provider.Telephony.SMS_RECEIVED
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * This class serves two purposes:
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * - Process phone verification SMS messages
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * - Handle SMS messages when the user has enabled us to be the default SMS app (Pre-KLP)
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic final class SmsReceiver extends BroadcastReceiver {
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String TAG = LogUtil.BUGLE_TAG;
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static ArrayList<Pattern> sIgnoreSmsPatterns;
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Enable or disable the SmsReceiver as appropriate. Pre-KLP we use this receiver for
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * receiving incoming SMS messages. For KLP+ this receiver is not used when running as the
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * primary user and the SmsDeliverReceiver is used for receiving incoming SMS messages.
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * When running as a secondary user, this receiver is still used to trigger the incoming
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * notification.
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void updateSmsReceiveHandler(final Context context) {
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean smsReceiverEnabled;
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean mmsWapPushReceiverEnabled;
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean respondViaMessageEnabled;
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean broadcastAbortEnabled;
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (OsUtil.isAtLeastKLP()) {
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // When we're running as the secondary user, we don't get the new SMS_DELIVER intent,
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // only the primary user receives that. As secondary, we need to go old-school and
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // listen for the SMS_RECEIVED intent. For the secondary user, use this SmsReceiver
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // for both sms and mms notification. For the primary user on KLP (and above), we don't
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // use the SmsReceiver.
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            smsReceiverEnabled = OsUtil.isSecondaryUser();
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // On KLP use the new deliver event for mms
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mmsWapPushReceiverEnabled = false;
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // On KLP we need to always enable this handler to show in the list of sms apps
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            respondViaMessageEnabled = true;
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // On KLP we don't need to abort the broadcast
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            broadcastAbortEnabled = false;
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // On JB we use the sms receiver for both sms/mms delivery
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final boolean carrierSmsEnabled = PhoneUtils.getDefault().isSmsEnabled();
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            smsReceiverEnabled = carrierSmsEnabled;
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // On JB we use the mms receiver when sms/mms is enabled
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mmsWapPushReceiverEnabled = carrierSmsEnabled;
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // On JB this is dynamic to make sure we don't show in dialer if sms is disabled
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            respondViaMessageEnabled = carrierSmsEnabled;
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // On JB we need to abort broadcasts if SMS is enabled
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            broadcastAbortEnabled = carrierSmsEnabled;
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final PackageManager packageManager = context.getPackageManager();
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean logv = LogUtil.isLoggable(TAG, LogUtil.VERBOSE);
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (smsReceiverEnabled) {
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (logv) {
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.v(TAG, "Enabling SMS message receiving");
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            packageManager.setComponentEnabledSetting(
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new ComponentName(context, SmsReceiver.class),
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (logv) {
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.v(TAG, "Disabling SMS message receiving");
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            packageManager.setComponentEnabledSetting(
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new ComponentName(context, SmsReceiver.class),
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mmsWapPushReceiverEnabled) {
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (logv) {
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.v(TAG, "Enabling MMS message receiving");
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            packageManager.setComponentEnabledSetting(
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new ComponentName(context, MmsWapPushReceiver.class),
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (logv) {
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.v(TAG, "Disabling MMS message receiving");
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            packageManager.setComponentEnabledSetting(
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new ComponentName(context, MmsWapPushReceiver.class),
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (broadcastAbortEnabled) {
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (logv) {
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.v(TAG, "Enabling SMS/MMS broadcast abort");
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            packageManager.setComponentEnabledSetting(
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new ComponentName(context, AbortSmsReceiver.class),
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            packageManager.setComponentEnabledSetting(
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new ComponentName(context, AbortMmsWapPushReceiver.class),
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (logv) {
151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.v(TAG, "Disabling SMS/MMS broadcast abort");
152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            packageManager.setComponentEnabledSetting(
154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new ComponentName(context, AbortSmsReceiver.class),
155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            packageManager.setComponentEnabledSetting(
157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new ComponentName(context, AbortMmsWapPushReceiver.class),
158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (respondViaMessageEnabled) {
161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (logv) {
162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.v(TAG, "Enabling respond via message intent");
163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            packageManager.setComponentEnabledSetting(
165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new ComponentName(context, NoConfirmationSmsSendService.class),
166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (logv) {
169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.v(TAG, "Disabling respond via message intent");
170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            packageManager.setComponentEnabledSetting(
172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new ComponentName(context, NoConfirmationSmsSendService.class),
173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String EXTRA_ERROR_CODE = "errorCode";
178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String EXTRA_SUB_ID = "subscription";
179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void deliverSmsIntent(final Context context, final Intent intent) {
181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final android.telephony.SmsMessage[] messages = getMessagesFromIntent(intent);
182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Check messages for validity
184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (messages == null || messages.length < 1) {
185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.e(TAG, "processReceivedSms: null or zero or ignored message");
186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return;
187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int errorCode = intent.getIntExtra(EXTRA_ERROR_CODE, 0);
190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Always convert negative subIds into -1
191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int subId = PhoneUtils.getDefault().getEffectiveIncomingSubIdFromSystem(
192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                intent, EXTRA_SUB_ID);
193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        deliverSmsMessages(context, subId, errorCode, messages);
194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (MmsUtils.isDumpSmsEnabled()) {
195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String format = null;
196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            DebugUtils.dumpSms(messages[0].getTimestampMillis(), messages, format);
197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void deliverSmsMessages(final Context context, final int subId,
201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int errorCode, final android.telephony.SmsMessage[] messages) {
202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ContentValues messageValues =
203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                MmsUtils.parseReceivedSmsMessage(context, messages, errorCode);
204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LogUtil.v(TAG, "SmsReceiver.deliverSmsMessages");
206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long nowInMillis =  System.currentTimeMillis();
208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long receivedTimestampMs = MmsUtils.getMessageDate(messages[0], nowInMillis);
209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        messageValues.put(Sms.Inbox.DATE, receivedTimestampMs);
211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Default to unread and unseen for us but ReceiveSmsMessageAction will override
212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // seen for the telephony db.
213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        messageValues.put(Sms.Inbox.READ, 0);
214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        messageValues.put(Sms.Inbox.SEEN, 0);
215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (OsUtil.isAtLeastL_MR1()) {
216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            messageValues.put(Sms.SUBSCRIPTION_ID, subId);
217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (messages[0].getMessageClass() == android.telephony.SmsMessage.MessageClass.CLASS_0 ||
220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                DebugUtils.debugClassZeroSmsEnabled()) {
221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Factory.get().getUIIntents().launchClassZeroActivity(context, messageValues);
222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ReceiveSmsMessageAction action = new ReceiveSmsMessageAction(messageValues);
224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            action.start();
225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void onReceive(final Context context, final Intent intent) {
230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LogUtil.v(TAG, "SmsReceiver.onReceive " + intent);
231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // On KLP+ we only take delivery of SMS messages in SmsDeliverReceiver.
232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (PhoneUtils.getDefault().isSmsEnabled()) {
233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String action = intent.getAction();
234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (OsUtil.isSecondaryUser() &&
235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    (Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(action) ||
236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            // TODO: update this with the actual constant from Telephony
237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            "android.provider.Telephony.MMS_DOWNLOADED".equals(action))) {
238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                postNewMessageSecondaryUserNotification();
239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else if (!OsUtil.isAtLeastKLP()) {
240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                deliverSmsIntent(context, intent);
241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static class SecondaryUserNotificationState extends MessageNotificationState {
246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        SecondaryUserNotificationState() {
247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            super(null);
248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        protected Style build(Builder builder) {
252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return null;
253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean getNotificationVibrate() {
257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return true;
258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void postNewMessageSecondaryUserNotification() {
262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Context context = Factory.get().getApplicationContext();
263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Resources resources = context.getResources();
264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final PendingIntent pendingIntent = UIIntents.get()
265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                .getPendingIntentForSecondaryUserNewMessageNotification(context);
266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        builder.setContentTitle(resources.getString(R.string.secondary_user_new_message_title))
269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                .setTicker(resources.getString(R.string.secondary_user_new_message_ticker))
270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                .setSmallIcon(R.drawable.ic_sms_light)
271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Returning PRIORITY_HIGH causes L to put up a HUD notification. Without it, the ticker
272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // isn't displayed.
273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                .setPriority(Notification.PRIORITY_HIGH)
274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                .setContentIntent(pendingIntent);
275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final NotificationCompat.BigTextStyle bigTextStyle =
277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                new NotificationCompat.BigTextStyle(builder);
278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        bigTextStyle.bigText(resources.getString(R.string.secondary_user_new_message_title));
279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Notification notification = bigTextStyle.build();
280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final NotificationManagerCompat notificationManager =
282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                NotificationManagerCompat.from(Factory.get().getApplicationContext());
283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int defaults = Notification.DEFAULT_LIGHTS;
285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (BugleNotifications.shouldVibrate(new SecondaryUserNotificationState())) {
286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            defaults |= Notification.DEFAULT_VIBRATE;
287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        notification.defaults = defaults;
289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        notificationManager.notify(getNotificationTag(),
291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                PendingIntentConstants.SMS_SECONDARY_USER_NOTIFICATION_ID, notification);
292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Cancel the notification
296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
297d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void cancelSecondaryUserNotification() {
298d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final NotificationManagerCompat notificationManager =
299d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                NotificationManagerCompat.from(Factory.get().getApplicationContext());
300d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        notificationManager.cancel(getNotificationTag(),
301d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                PendingIntentConstants.SMS_SECONDARY_USER_NOTIFICATION_ID);
302d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
303d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
304d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static String getNotificationTag() {
305d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return Factory.get().getApplicationContext().getPackageName() + ":secondaryuser";
306d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
307d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
308d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
309d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Compile all of the patterns we check for to ignore system SMS messages.
310d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static void compileIgnoreSmsPatterns() {
312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Get the pattern set from GServices
313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String smsIgnoreRegex = BugleGservices.get().getString(
314d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                BugleGservicesKeys.SMS_IGNORE_MESSAGE_REGEX,
315d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                BugleGservicesKeys.SMS_IGNORE_MESSAGE_REGEX_DEFAULT);
316d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (smsIgnoreRegex != null) {
317d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String[] ignoreSmsExpressions = smsIgnoreRegex.split("\n");
318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (ignoreSmsExpressions.length != 0) {
319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                sIgnoreSmsPatterns = new ArrayList<Pattern>();
320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                for (int i = 0; i < ignoreSmsExpressions.length; i++) {
321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    try {
322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        sIgnoreSmsPatterns.add(Pattern.compile(ignoreSmsExpressions[i]));
323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    } catch (PatternSyntaxException e) {
324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        LogUtil.e(TAG, "compileIgnoreSmsPatterns: Skipping bad expression: " +
325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                ignoreSmsExpressions[i]);
326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
332d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
333d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get the SMS messages from the specified SMS intent.
334d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the messages. If there is an error or the message should be ignored, return null.
335d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
336d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static android.telephony.SmsMessage[] getMessagesFromIntent(Intent intent) {
337d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final android.telephony.SmsMessage[] messages = Sms.Intents.getMessagesFromIntent(intent);
338d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
339d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Check messages for validity
340d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (messages == null || messages.length < 1) {
341d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return null;
342d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
343d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Sometimes, SmsMessage.mWrappedSmsMessage is null causing NPE when we access
344d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // the methods on it although the SmsMessage itself is not null. So do this check
345d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // before we do anything on the parsed SmsMessages.
346d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
347d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String messageBody = messages[0].getDisplayMessageBody();
348d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (messageBody != null) {
349d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Compile patterns if necessary
350d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (sIgnoreSmsPatterns == null) {
351d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    compileIgnoreSmsPatterns();
352d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
353d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Check against filters
354d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                for (final Pattern pattern : sIgnoreSmsPatterns) {
355d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (pattern.matcher(messageBody).matches()) {
356d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        return null;
357d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
358d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
359d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
360d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final NullPointerException e) {
361d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.e(TAG, "shouldIgnoreMessage: NPE inside SmsMessage");
362d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return null;
363d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
364d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return messages;
365d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
366d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
367d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
368d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
369d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Check the specified SMS intent to see if the message should be ignored
370d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return true if the message should be ignored
371d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
372d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean shouldIgnoreMessage(Intent intent) {
373d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return getMessagesFromIntent(intent) == null;
374d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
375d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
376