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.cellbroadcastreceiver;
18 
19 import android.content.Context;
20 import android.database.Cursor;
21 import android.provider.Telephony;
22 import android.telephony.SmsCbCmasInfo;
23 import android.telephony.SmsCbEtwsInfo;
24 import android.telephony.SmsCbLocation;
25 import android.telephony.SmsCbMessage;
26 import android.telephony.SubscriptionManager;
27 import android.view.LayoutInflater;
28 import android.view.View;
29 import android.view.ViewGroup;
30 import android.widget.CheckedTextView;
31 import android.widget.CursorAdapter;
32 import android.widget.ListView;
33 
34 import com.android.internal.annotations.VisibleForTesting;
35 import com.android.modules.utils.build.SdkLevel;
36 
37 /**
38  * The back-end data adapter for {@link CellBroadcastListActivity}.
39  */
40 public class CellBroadcastCursorAdapter extends CursorAdapter {
41 
42     private boolean mIsActionMode = false;
43     private CheckedTextView mCheckedTextView;
44     private ListView mListView;
45 
CellBroadcastCursorAdapter(Context context, ListView listview)46     public CellBroadcastCursorAdapter(Context context, ListView listview) {
47         // don't set FLAG_AUTO_REQUERY or FLAG_REGISTER_CONTENT_OBSERVER
48         super(context, null, 0);
49         mListView = listview;
50     }
51 
52     /**
53      * Makes a new view to hold the data pointed to by cursor.
54      * @param context Interface to application's global information
55      * @param cursor The cursor from which to get the data. The cursor is already
56      * moved to the correct position.
57      * @param parent The parent to which the new view is attached to
58      * @return the newly created view.
59      */
60     @Override
newView(Context context, Cursor cursor, ViewGroup parent)61     public View newView(Context context, Cursor cursor, ViewGroup parent) {
62         SmsCbMessage message = createFromCursor(context, cursor);
63 
64         LayoutInflater factory = LayoutInflater.from(context);
65         CellBroadcastListItem listItem = (CellBroadcastListItem) factory.inflate(
66                     R.layout.cell_broadcast_list_item, parent, false);
67 
68         listItem.bind(message);
69         return listItem;
70     }
71 
createFromCursor(Context context, Cursor cursor)72     static SmsCbMessage createFromCursor(Context context, Cursor cursor) {
73         int geoScope = cursor.getInt(
74                 cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.GEOGRAPHICAL_SCOPE));
75         int serialNum = cursor.getInt(
76                 cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.SERIAL_NUMBER));
77         int category = cursor.getInt(
78                 cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.SERVICE_CATEGORY));
79         String language = cursor.getString(
80                 cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.LANGUAGE_CODE));
81         String body = cursor.getString(
82                 cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.MESSAGE_BODY));
83         int format = cursor.getInt(
84                 cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.MESSAGE_FORMAT));
85         int priority = cursor.getInt(
86                 cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.MESSAGE_PRIORITY));
87         int slotIndex = cursor.getInt(
88                 cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.SLOT_INDEX));
89 
90         String plmn;
91         int plmnColumn = cursor.getColumnIndex(Telephony.CellBroadcasts.PLMN);
92         if (plmnColumn != -1 && !cursor.isNull(plmnColumn)) {
93             plmn = cursor.getString(plmnColumn);
94         } else {
95             plmn = null;
96         }
97 
98         int lac;
99         int lacColumn = cursor.getColumnIndex(Telephony.CellBroadcasts.LAC);
100         if (lacColumn != -1 && !cursor.isNull(lacColumn)) {
101             lac = cursor.getInt(lacColumn);
102         } else {
103             lac = -1;
104         }
105 
106         int cid;
107         int cidColumn = cursor.getColumnIndex(Telephony.CellBroadcasts.CID);
108         if (cidColumn != -1 && !cursor.isNull(cidColumn)) {
109             cid = cursor.getInt(cidColumn);
110         } else {
111             cid = -1;
112         }
113 
114         SmsCbLocation location = new SmsCbLocation(plmn, lac, cid);
115 
116         SmsCbEtwsInfo etwsInfo;
117         int etwsWarningTypeColumn = cursor.getColumnIndex(
118                 Telephony.CellBroadcasts.ETWS_WARNING_TYPE);
119         if (etwsWarningTypeColumn != -1 && !cursor.isNull(etwsWarningTypeColumn)) {
120             int warningType = cursor.getInt(etwsWarningTypeColumn);
121             etwsInfo = new SmsCbEtwsInfo(warningType, false, false, false, null);
122         } else {
123             etwsInfo = null;
124         }
125 
126         SmsCbCmasInfo cmasInfo;
127         int cmasMessageClassColumn = cursor.getColumnIndex(
128                 Telephony.CellBroadcasts.CMAS_MESSAGE_CLASS);
129         if (cmasMessageClassColumn != -1 && !cursor.isNull(cmasMessageClassColumn)) {
130             int messageClass = cursor.getInt(cmasMessageClassColumn);
131 
132             int cmasCategory;
133             int cmasCategoryColumn = cursor.getColumnIndex(
134                     Telephony.CellBroadcasts.CMAS_CATEGORY);
135             if (cmasCategoryColumn != -1 && !cursor.isNull(cmasCategoryColumn)) {
136                 cmasCategory = cursor.getInt(cmasCategoryColumn);
137             } else {
138                 cmasCategory = SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN;
139             }
140 
141             int responseType;
142             int cmasResponseTypeColumn = cursor.getColumnIndex(
143                     Telephony.CellBroadcasts.CMAS_RESPONSE_TYPE);
144             if (cmasResponseTypeColumn != -1 && !cursor.isNull(cmasResponseTypeColumn)) {
145                 responseType = cursor.getInt(cmasResponseTypeColumn);
146             } else {
147                 responseType = SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN;
148             }
149 
150             int severity;
151             int cmasSeverityColumn = cursor.getColumnIndex(
152                     Telephony.CellBroadcasts.CMAS_SEVERITY);
153             if (cmasSeverityColumn != -1 && !cursor.isNull(cmasSeverityColumn)) {
154                 severity = cursor.getInt(cmasSeverityColumn);
155             } else {
156                 severity = SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN;
157             }
158 
159             int urgency;
160             int cmasUrgencyColumn = cursor.getColumnIndex(
161                     Telephony.CellBroadcasts.CMAS_URGENCY);
162             if (cmasUrgencyColumn != -1 && !cursor.isNull(cmasUrgencyColumn)) {
163                 urgency = cursor.getInt(cmasUrgencyColumn);
164             } else {
165                 urgency = SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN;
166             }
167 
168             int certainty;
169             int cmasCertaintyColumn = cursor.getColumnIndex(
170                     Telephony.CellBroadcasts.CMAS_CERTAINTY);
171             if (cmasCertaintyColumn != -1 && !cursor.isNull(cmasCertaintyColumn)) {
172                 certainty = cursor.getInt(cmasCertaintyColumn);
173             } else {
174                 certainty = SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN;
175             }
176 
177             cmasInfo = new SmsCbCmasInfo(messageClass, cmasCategory, responseType, severity,
178                     urgency, certainty);
179         } else {
180             cmasInfo = null;
181         }
182 
183         String timeColumn = null;
184         if (cursor.getColumnIndex(Telephony.CellBroadcasts.DELIVERY_TIME) >= 0) {
185             timeColumn = Telephony.CellBroadcasts.DELIVERY_TIME;
186         } else if (cursor.getColumnIndex(Telephony.CellBroadcasts.RECEIVED_TIME) >= 0) {
187             timeColumn = Telephony.CellBroadcasts.RECEIVED_TIME;
188         }
189 
190         long time = cursor.getLong(cursor.getColumnIndexOrThrow(timeColumn));
191 
192         int dcs = 0;
193         if (cursor.getColumnIndex(Telephony.CellBroadcasts.DATA_CODING_SCHEME) >= 0) {
194             dcs = cursor.getInt(cursor.getColumnIndexOrThrow(
195                     Telephony.CellBroadcasts.DATA_CODING_SCHEME));
196         }
197 
198         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
199         if (SdkLevel.isAtLeastU()) {
200             subId = SubscriptionManager.getSubscriptionId(slotIndex);
201         } else {
202             SubscriptionManager sm = context.getSystemService(SubscriptionManager.class);
203             int[] subIds = sm.getSubscriptionIds(slotIndex);
204             if (subIds != null && subIds.length > 0) {
205                 subId = subIds[0];
206             }
207         }
208 
209         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
210             subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
211         }
212 
213         int maximumWaitTimeSec = 0;
214         if (cursor.getColumnIndex(Telephony.CellBroadcasts.MAXIMUM_WAIT_TIME) >= 0) {
215             maximumWaitTimeSec = cursor.getInt(cursor.getColumnIndexOrThrow(
216                     Telephony.CellBroadcasts.MAXIMUM_WAIT_TIME));
217         }
218 
219         return new SmsCbMessage(format, geoScope, serialNum, location, category, language, dcs,
220                 body, priority, etwsInfo, cmasInfo, maximumWaitTimeSec, null, time,
221                 slotIndex, subId);
222     }
223 
224     /**
225      * Bind an existing view to the data pointed to by cursor
226      * @param view Existing view, returned earlier by newView
227      * @param context Interface to application's global information
228      * @param cursor The cursor from which to get the data. The cursor is already
229      * moved to the correct position.
230      */
231     @Override
bindView(View view, Context context, Cursor cursor)232     public void bindView(View view, Context context, Cursor cursor) {
233         SmsCbMessage message = createFromCursor(context, cursor);
234         CellBroadcastListItem listItem = (CellBroadcastListItem) view;
235         mCheckedTextView = view.findViewById(R.id.checkBox);
236         if (mCheckedTextView != null) {
237             updateCheckTextViewVisibility();
238             checkIsSelected(cursor.getPosition());
239         }
240         listItem.bind(message);
241     }
242 
setIsActionMode(boolean value)243     public void setIsActionMode(boolean value) {
244         mIsActionMode = value;
245     }
246 
247     @VisibleForTesting
getIsActionMode()248     public boolean getIsActionMode() {
249         return mIsActionMode;
250     }
251 
updateCheckTextViewVisibility()252     void updateCheckTextViewVisibility() {
253         if (mIsActionMode) {
254             mCheckedTextView.setVisibility(View.VISIBLE);
255         } else {
256             mCheckedTextView.setVisibility(View.GONE);
257         }
258     }
259 
checkIsSelected(int position)260     void checkIsSelected(int position) {
261         boolean isChecked = mListView.isItemChecked(position);
262         mCheckedTextView.setChecked(isChecked);
263     }
264 }
265