1/*
2 * Copyright (C) 2008 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
18package com.android.internal.telephony.cdma;
19
20import android.content.Context;
21import android.os.AsyncResult;
22import android.os.Handler;
23import android.os.Message;
24import android.util.Log;
25
26import com.android.internal.telephony.IccConstants;
27import com.android.internal.telephony.IccSmsInterfaceManager;
28import com.android.internal.telephony.IccUtils;
29import com.android.internal.telephony.PhoneProxy;
30import com.android.internal.telephony.SMSDispatcher;
31import com.android.internal.telephony.SmsRawData;
32
33import java.util.ArrayList;
34import java.util.Arrays;
35import java.util.List;
36
37import static android.telephony.SmsManager.STATUS_ON_ICC_FREE;
38
39/**
40 * RuimSmsInterfaceManager to provide an inter-process communication to
41 * access Sms in Ruim.
42 */
43public class RuimSmsInterfaceManager extends IccSmsInterfaceManager {
44    static final String LOG_TAG = "CDMA";
45    static final boolean DBG = true;
46
47    private final Object mLock = new Object();
48    private boolean mSuccess;
49    private List<SmsRawData> mSms;
50
51    private static final int EVENT_LOAD_DONE = 1;
52    private static final int EVENT_UPDATE_DONE = 2;
53
54    Handler mHandler = new Handler() {
55        @Override
56        public void handleMessage(Message msg) {
57            AsyncResult ar;
58
59            switch (msg.what) {
60                case EVENT_UPDATE_DONE:
61                    ar = (AsyncResult) msg.obj;
62                    synchronized (mLock) {
63                        mSuccess = (ar.exception == null);
64                        mLock.notifyAll();
65                    }
66                    break;
67                case EVENT_LOAD_DONE:
68                    ar = (AsyncResult)msg.obj;
69                    synchronized (mLock) {
70                        if (ar.exception == null) {
71                            mSms = buildValidRawData((ArrayList<byte[]>) ar.result);
72                        } else {
73                            if(DBG) log("Cannot load Sms records");
74                            if (mSms != null)
75                                mSms.clear();
76                        }
77                        mLock.notifyAll();
78                    }
79                    break;
80            }
81        }
82    };
83
84    public RuimSmsInterfaceManager(CDMAPhone phone, SMSDispatcher dispatcher) {
85        super(phone);
86        mDispatcher = dispatcher;
87    }
88
89    public void dispose() {
90    }
91
92    protected void finalize() {
93        try {
94            super.finalize();
95        } catch (Throwable throwable) {
96            Log.e(LOG_TAG, "Error while finalizing:", throwable);
97        }
98        if(DBG) Log.d(LOG_TAG, "RuimSmsInterfaceManager finalized");
99    }
100
101    /**
102     * Update the specified message on the RUIM.
103     *
104     * @param index record index of message to update
105     * @param status new message status (STATUS_ON_ICC_READ,
106     *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
107     *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
108     * @param pdu the raw PDU to store
109     * @return success or not
110     *
111     */
112    public boolean
113    updateMessageOnIccEf(int index, int status, byte[] pdu) {
114        if (DBG) log("updateMessageOnIccEf: index=" + index +
115                " status=" + status + " ==> " +
116                "("+ pdu + ")");
117        enforceReceiveAndSend("Updating message on RUIM");
118        synchronized(mLock) {
119            mSuccess = false;
120            Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE);
121
122            if (status == STATUS_ON_ICC_FREE) {
123                // Special case FREE: call deleteSmsOnRuim instead of
124                // manipulating the RUIM record
125                mPhone.mCM.deleteSmsOnRuim(index, response);
126            } else {
127                byte[] record = makeSmsRecordData(status, pdu);
128                mPhone.getIccFileHandler().updateEFLinearFixed(
129                        IccConstants.EF_SMS, index, record, null, response);
130            }
131            try {
132                mLock.wait();
133            } catch (InterruptedException e) {
134                log("interrupted while trying to update by index");
135            }
136        }
137        return mSuccess;
138    }
139
140    /**
141     * Copy a raw SMS PDU to the RUIM.
142     *
143     * @param pdu the raw PDU to store
144     * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
145     *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
146     * @return success or not
147     *
148     */
149    public boolean copyMessageToIccEf(int status, byte[] pdu, byte[] smsc) {
150        //NOTE smsc not used in RUIM
151        if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " +
152                "pdu=("+ Arrays.toString(pdu) + ")");
153        enforceReceiveAndSend("Copying message to RUIM");
154        synchronized(mLock) {
155            mSuccess = false;
156            Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE);
157
158            mPhone.mCM.writeSmsToRuim(status, IccUtils.bytesToHexString(pdu),
159                    response);
160
161            try {
162                mLock.wait();
163            } catch (InterruptedException e) {
164                log("interrupted while trying to update by index");
165            }
166        }
167        return mSuccess;
168    }
169
170    /**
171     * Retrieves all messages currently stored on RUIM.
172     */
173    public List<SmsRawData> getAllMessagesFromIccEf() {
174        if (DBG) log("getAllMessagesFromEF");
175
176        Context context = mPhone.getContext();
177
178        context.enforceCallingPermission(
179                "android.permission.RECEIVE_SMS",
180                "Reading messages from RUIM");
181        synchronized(mLock) {
182            Message response = mHandler.obtainMessage(EVENT_LOAD_DONE);
183            mPhone.getIccFileHandler().loadEFLinearFixedAll(IccConstants.EF_SMS, response);
184
185            try {
186                mLock.wait();
187            } catch (InterruptedException e) {
188                log("interrupted while trying to load from the RUIM");
189            }
190        }
191        return mSms;
192    }
193
194    public boolean enableCellBroadcast(int messageIdentifier) {
195        // Not implemented
196        Log.e(LOG_TAG, "Error! Not implemented for CDMA.");
197        return false;
198    }
199
200    public boolean disableCellBroadcast(int messageIdentifier) {
201        // Not implemented
202        Log.e(LOG_TAG, "Error! Not implemented for CDMA.");
203        return false;
204    }
205
206    public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) {
207        // Not implemented
208        Log.e(LOG_TAG, "Error! Not implemented for CDMA.");
209        return false;
210    }
211
212    public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) {
213        // Not implemented
214        Log.e(LOG_TAG, "Error! Not implemented for CDMA.");
215        return false;
216    }
217
218    protected void log(String msg) {
219        Log.d(LOG_TAG, "[RuimSmsInterfaceManager] " + msg);
220    }
221}
222
223