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