1 /* 2 * Copyright (C) 2011 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; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.os.AsyncResult; 25 import android.os.Handler; 26 import android.os.Message; 27 import android.os.PowerManager; 28 import android.provider.Telephony.Sms.Intents; 29 import android.telephony.SubscriptionManager; 30 31 import com.android.telephony.Rlog; 32 33 /** 34 * Monitors the device and ICC storage, and sends the appropriate events. 35 * 36 * This code was formerly part of {@link SMSDispatcher}, and has been moved 37 * into a separate class to support instantiation of multiple SMSDispatchers on 38 * dual-mode devices that require support for both 3GPP and 3GPP2 format messages. 39 */ 40 public class SmsStorageMonitor extends Handler { 41 private static final String TAG = "SmsStorageMonitor"; 42 43 /** SIM/RUIM storage is full */ 44 private static final int EVENT_ICC_FULL = 1; 45 46 /** Memory status reporting is acknowledged by RIL */ 47 private static final int EVENT_REPORT_MEMORY_STATUS_DONE = 2; 48 49 /** Radio is ON */ 50 private static final int EVENT_RADIO_ON = 3; 51 52 /** Context from phone object passed to constructor. */ 53 private final Context mContext; 54 55 /** Wake lock to ensure device stays awake while dispatching the SMS intent. */ 56 private PowerManager.WakeLock mWakeLock; 57 58 private boolean mReportMemoryStatusPending; 59 60 /** it is use to put in to extra value for SIM_FULL_ACTION and SMS_REJECTED_ACTION */ 61 Phone mPhone; 62 63 @UnsupportedAppUsage 64 final CommandsInterface mCi; // accessed from inner class 65 boolean mStorageAvailable = true; // accessed from inner class 66 67 /** 68 * Hold the wake lock for 5 seconds, which should be enough time for 69 * any receiver(s) to grab its own wake lock. 70 */ 71 private static final int WAKE_LOCK_TIMEOUT = 5000; 72 73 /** 74 * Creates an SmsStorageMonitor and registers for events. 75 * @param phone the Phone to use 76 */ SmsStorageMonitor(Phone phone)77 public SmsStorageMonitor(Phone phone) { 78 mPhone = phone; 79 mContext = phone.getContext(); 80 mCi = phone.mCi; 81 82 createWakelock(); 83 84 mCi.setOnIccSmsFull(this, EVENT_ICC_FULL, null); 85 mCi.registerForOn(this, EVENT_RADIO_ON, null); 86 87 // Register for device storage intents. Use these to notify the RIL 88 // that storage for SMS is or is not available. 89 IntentFilter filter = new IntentFilter(); 90 filter.addAction(Intent.ACTION_DEVICE_STORAGE_FULL); 91 filter.addAction(Intent.ACTION_DEVICE_STORAGE_NOT_FULL); 92 mContext.registerReceiver(mResultReceiver, filter); 93 } 94 dispose()95 public void dispose() { 96 mCi.unSetOnIccSmsFull(this); 97 mCi.unregisterForOn(this); 98 mContext.unregisterReceiver(mResultReceiver); 99 } 100 101 /** 102 * Handles events coming from the phone stack. Overridden from handler. 103 * @param msg the message to handle 104 */ 105 @Override handleMessage(Message msg)106 public void handleMessage(Message msg) { 107 AsyncResult ar; 108 109 switch (msg.what) { 110 case EVENT_ICC_FULL: 111 handleIccFull(); 112 break; 113 114 case EVENT_REPORT_MEMORY_STATUS_DONE: 115 ar = (AsyncResult) msg.obj; 116 if (ar.exception != null) { 117 mReportMemoryStatusPending = true; 118 Rlog.v(TAG, "Memory status report to modem pending : mStorageAvailable = " 119 + mStorageAvailable); 120 } else { 121 mReportMemoryStatusPending = false; 122 } 123 break; 124 125 case EVENT_RADIO_ON: 126 if (mReportMemoryStatusPending) { 127 Rlog.v(TAG, "Sending pending memory status report : mStorageAvailable = " 128 + mStorageAvailable); 129 mCi.reportSmsMemoryStatus(mStorageAvailable, 130 obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE)); 131 } 132 break; 133 } 134 } 135 createWakelock()136 private void createWakelock() { 137 PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 138 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SmsStorageMonitor"); 139 mWakeLock.setReferenceCounted(true); 140 } 141 142 /** 143 * Called when SIM_FULL message is received from the RIL. Notifies the default SMS application 144 * that SIM storage for SMS messages is full. 145 */ handleIccFull()146 private void handleIccFull() { 147 // broadcast SIM_FULL intent 148 Intent intent = new Intent(Intents.SIM_FULL_ACTION); 149 intent.setComponent(SmsApplication.getDefaultSimFullApplication(mContext, false)); 150 mWakeLock.acquire(WAKE_LOCK_TIMEOUT); 151 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); 152 mContext.sendBroadcast(intent, android.Manifest.permission.RECEIVE_SMS); 153 } 154 155 /** Returns whether or not there is storage available for an incoming SMS. */ isStorageAvailable()156 public boolean isStorageAvailable() { 157 return mStorageAvailable; 158 } 159 160 private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() { 161 @Override 162 public void onReceive(Context context, Intent intent) { 163 if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_FULL)) { 164 mStorageAvailable = false; 165 mCi.reportSmsMemoryStatus(false, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE)); 166 } else if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_NOT_FULL)) { 167 mStorageAvailable = true; 168 mCi.reportSmsMemoryStatus(true, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE)); 169 } 170 } 171 }; 172 } 173