blob: 13d1c3aac43b8887e92850a0c5a4cfaa52b0f80a [file] [log] [blame]
SongFerngWang1bb5a6f2019-12-10 00:42:54 +08001/*
2 * Copyright (C) 2019 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
17package com.android.phone;
18
19import static android.provider.Telephony.ServiceStateTable;
SongFerngWang1bb5a6f2019-12-10 00:42:54 +080020import static android.provider.Telephony.ServiceStateTable.CONTENT_URI;
Rambo Wangfbdb3482021-03-15 21:14:19 -070021import static android.provider.Telephony.ServiceStateTable.DATA_NETWORK_TYPE;
Rambo Wang917ee2f2021-03-15 12:15:51 -070022import static android.provider.Telephony.ServiceStateTable.DUPLEX_MODE;
SongFerngWang1bb5a6f2019-12-10 00:42:54 +080023import static android.provider.Telephony.ServiceStateTable.IS_MANUAL_NETWORK_SELECTION;
SongFerngWang1bb5a6f2019-12-10 00:42:54 +080024import static android.provider.Telephony.ServiceStateTable.VOICE_REG_STATE;
SongFerngWang1bb5a6f2019-12-10 00:42:54 +080025import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionId;
26import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionIdAndField;
27
28import android.content.ContentProvider;
29import android.content.ContentValues;
30import android.content.Context;
31import android.database.Cursor;
32import android.database.MatrixCursor;
33import android.database.MatrixCursor.RowBuilder;
34import android.net.Uri;
35import android.os.Parcel;
36import android.telephony.ServiceState;
37import android.telephony.SubscriptionManager;
38import android.util.Log;
39
40import com.android.internal.annotations.VisibleForTesting;
41
42import java.util.HashMap;
Grace Jia1ca70d02020-01-16 14:13:12 -080043import java.util.List;
44import java.util.Objects;
SongFerngWang1bb5a6f2019-12-10 00:42:54 +080045
46/**
47 * The class to provide base facility to access ServiceState related content,
48 * which is stored in a SQLite database.
49 */
50public class ServiceStateProvider extends ContentProvider {
51 private static final String TAG = "ServiceStateProvider";
52
53 public static final String AUTHORITY = ServiceStateTable.AUTHORITY;
54 public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
55
Grace Jiadd25f0e2020-01-21 12:35:28 -080056 /**
57 * The current service state.
58 *
59 * This is the entire {@link ServiceState} object in byte array.
60 *
61 * @hide
62 */
63 public static final String SERVICE_STATE = "service_state";
64
65 /**
66 * An integer value indicating the current data service state.
67 * <p>
68 * Valid values: {@link ServiceState#STATE_IN_SERVICE},
69 * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
70 * {@link ServiceState#STATE_POWER_OFF}.
71 * <p>
72 * This is the same as {@link ServiceState#getDataRegState()}.
73 * @hide
74 */
75 public static final String DATA_REG_STATE = "data_reg_state";
76
77 /**
78 * An integer value indicating the current voice roaming type.
79 * <p>
80 * This is the same as {@link ServiceState#getVoiceRoamingType()}.
81 * @hide
82 */
83 public static final String VOICE_ROAMING_TYPE = "voice_roaming_type";
84
85 /**
86 * An integer value indicating the current data roaming type.
87 * <p>
88 * This is the same as {@link ServiceState#getDataRoamingType()}.
89 * @hide
90 */
91 public static final String DATA_ROAMING_TYPE = "data_roaming_type";
92
93 /**
94 * The current registered voice network operator name in long alphanumeric format.
95 * <p>
96 * This is the same as {@link ServiceState#getOperatorAlphaLong()}.
97 * @hide
98 */
99 public static final String VOICE_OPERATOR_ALPHA_LONG = "voice_operator_alpha_long";
100
101 /**
102 * The current registered operator name in short alphanumeric format.
103 * <p>
104 * In GSM/UMTS, short format can be up to 8 characters long. The current registered voice
105 * network operator name in long alphanumeric format.
106 * <p>
107 * This is the same as {@link ServiceState#getOperatorAlphaShort()}.
108 * @hide
109 */
110 public static final String VOICE_OPERATOR_ALPHA_SHORT = "voice_operator_alpha_short";
111
112 /**
113 * The current registered operator numeric id.
114 * <p>
115 * In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit
116 * network code.
117 * <p>
118 * This is the same as {@link ServiceState#getOperatorNumeric()}.
119 */
120 public static final String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric";
121
122 /**
123 * The current registered data network operator name in long alphanumeric format.
124 * <p>
125 * This is the same as {@link ServiceState#getOperatorAlphaLong()}.
126 * @hide
127 */
128 public static final String DATA_OPERATOR_ALPHA_LONG = "data_operator_alpha_long";
129
130 /**
131 * The current registered data network operator name in short alphanumeric format.
132 * <p>
133 * This is the same as {@link ServiceState#getOperatorAlphaShort()}.
134 * @hide
135 */
136 public static final String DATA_OPERATOR_ALPHA_SHORT = "data_operator_alpha_short";
137
138 /**
139 * The current registered data network operator numeric id.
140 * <p>
141 * This is the same as {@link ServiceState#getOperatorNumeric()}.
142 * @hide
143 */
144 public static final String DATA_OPERATOR_NUMERIC = "data_operator_numeric";
145
146 /**
147 * This is the same as {@link ServiceState#getRilVoiceRadioTechnology()}.
148 * @hide
149 */
150 public static final String RIL_VOICE_RADIO_TECHNOLOGY = "ril_voice_radio_technology";
151
152 /**
153 * This is the same as {@link ServiceState#getRilDataRadioTechnology()}.
154 * @hide
155 */
156 public static final String RIL_DATA_RADIO_TECHNOLOGY = "ril_data_radio_technology";
157
158 /**
159 * This is the same as {@link ServiceState#getCssIndicator()}.
160 * @hide
161 */
162 public static final String CSS_INDICATOR = "css_indicator";
163
164 /**
165 * This is the same as {@link ServiceState#getCdmaNetworkId()}.
166 * @hide
167 */
168 public static final String NETWORK_ID = "network_id";
169
170 /**
171 * This is the same as {@link ServiceState#getCdmaSystemId()}.
172 * @hide
173 */
174 public static final String SYSTEM_ID = "system_id";
175
176 /**
177 * This is the same as {@link ServiceState#getCdmaRoamingIndicator()}.
178 * @hide
179 */
180 public static final String CDMA_ROAMING_INDICATOR = "cdma_roaming_indicator";
181
182 /**
183 * This is the same as {@link ServiceState#getCdmaDefaultRoamingIndicator()}.
184 * @hide
185 */
186 public static final String CDMA_DEFAULT_ROAMING_INDICATOR =
187 "cdma_default_roaming_indicator";
188
189 /**
190 * This is the same as {@link ServiceState#getCdmaEriIconIndex()}.
191 * @hide
192 */
193 public static final String CDMA_ERI_ICON_INDEX = "cdma_eri_icon_index";
194
195 /**
196 * This is the same as {@link ServiceState#getCdmaEriIconMode()}.
197 * @hide
198 */
199 public static final String CDMA_ERI_ICON_MODE = "cdma_eri_icon_mode";
200
201 /**
202 * This is the same as {@link ServiceState#isEmergencyOnly()}.
203 * @hide
204 */
205 public static final String IS_EMERGENCY_ONLY = "is_emergency_only";
206
207 /**
208 * This is the same as {@link ServiceState#getDataRoamingFromRegistration()}.
209 * @hide
210 */
211 public static final String IS_DATA_ROAMING_FROM_REGISTRATION =
212 "is_data_roaming_from_registration";
213
214 /**
215 * This is the same as {@link ServiceState#isUsingCarrierAggregation()}.
216 * @hide
217 */
218 public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation";
219
220 /**
221 * The current registered raw data network operator name in long alphanumeric format.
222 * <p>
223 * This is the same as {@link ServiceState#getOperatorAlphaLongRaw()}.
224 * @hide
225 */
226 public static final String OPERATOR_ALPHA_LONG_RAW = "operator_alpha_long_raw";
227
228 /**
229 * The current registered raw data network operator name in short alphanumeric format.
230 * <p>
231 * This is the same as {@link ServiceState#getOperatorAlphaShortRaw()}.
232 * @hide
233 */
234 public static final String OPERATOR_ALPHA_SHORT_RAW = "operator_alpha_short_raw";
235
SongFerngWang1bb5a6f2019-12-10 00:42:54 +0800236 private final HashMap<Integer, ServiceState> mServiceStates = new HashMap<>();
237 private static final String[] sColumns = {
238 VOICE_REG_STATE,
239 DATA_REG_STATE,
240 VOICE_ROAMING_TYPE,
241 DATA_ROAMING_TYPE,
242 VOICE_OPERATOR_ALPHA_LONG,
243 VOICE_OPERATOR_ALPHA_SHORT,
244 VOICE_OPERATOR_NUMERIC,
245 DATA_OPERATOR_ALPHA_LONG,
246 DATA_OPERATOR_ALPHA_SHORT,
247 DATA_OPERATOR_NUMERIC,
248 IS_MANUAL_NETWORK_SELECTION,
249 RIL_VOICE_RADIO_TECHNOLOGY,
250 RIL_DATA_RADIO_TECHNOLOGY,
251 CSS_INDICATOR,
252 NETWORK_ID,
253 SYSTEM_ID,
254 CDMA_ROAMING_INDICATOR,
255 CDMA_DEFAULT_ROAMING_INDICATOR,
256 CDMA_ERI_ICON_INDEX,
257 CDMA_ERI_ICON_MODE,
258 IS_EMERGENCY_ONLY,
259 IS_USING_CARRIER_AGGREGATION,
260 OPERATOR_ALPHA_LONG_RAW,
261 OPERATOR_ALPHA_SHORT_RAW,
Rambo Wangfbdb3482021-03-15 21:14:19 -0700262 DATA_NETWORK_TYPE,
Rambo Wang917ee2f2021-03-15 12:15:51 -0700263 DUPLEX_MODE,
SongFerngWang1bb5a6f2019-12-10 00:42:54 +0800264 };
265
266 @Override
267 public boolean onCreate() {
268 return true;
269 }
270
271 /**
272 * Returns the {@link ServiceState} information on specified subscription.
273 *
274 * @param subId whose subscriber id is returned
275 * @return the {@link ServiceState} information on specified subscription.
276 */
277 @VisibleForTesting
278 public ServiceState getServiceState(int subId) {
279 return mServiceStates.get(subId);
280 }
281
282 /**
283 * Returns the system's default subscription id.
284 *
285 * @return the "system" default subscription id.
286 */
287 @VisibleForTesting
288 public int getDefaultSubId() {
289 return SubscriptionManager.getDefaultSubscriptionId();
290 }
291
292 @Override
293 public Uri insert(Uri uri, ContentValues values) {
Grace Jia1ca70d02020-01-16 14:13:12 -0800294 if (isPathPrefixMatch(uri, CONTENT_URI)) {
SongFerngWang1bb5a6f2019-12-10 00:42:54 +0800295 // Parse the subId
296 int subId = 0;
297 try {
298 subId = Integer.parseInt(uri.getLastPathSegment());
299 } catch (NumberFormatException e) {
300 Log.e(TAG, "insert: no subId provided in uri");
301 throw e;
302 }
303 Log.d(TAG, "subId=" + subId);
304
305 // handle DEFAULT_SUBSCRIPTION_ID
306 if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
307 subId = getDefaultSubId();
308 }
309
310 final Parcel p = Parcel.obtain();
311 final byte[] rawBytes = values.getAsByteArray(SERVICE_STATE);
312 p.unmarshall(rawBytes, 0, rawBytes.length);
313 p.setDataPosition(0);
314
315 // create the new service state
316 final ServiceState newSS = ServiceState.CREATOR.createFromParcel(p);
317
318 // notify listeners
319 // if ss is null (e.g. first service state update) we will notify for all fields
320 ServiceState ss = getServiceState(subId);
321 notifyChangeForSubIdAndField(getContext(), ss, newSS, subId);
322 notifyChangeForSubId(getContext(), ss, newSS, subId);
323
324 // store the new service state
325 mServiceStates.put(subId, newSS);
326 return uri;
327 }
328 return null;
329 }
330
331 @Override
332 public int delete(Uri uri, String selection, String[] selectionArgs) {
333 throw new RuntimeException("Not supported");
334 }
335
336 @Override
337 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
338 throw new RuntimeException("Not supported");
339 }
340
341 @Override
342 public String getType(Uri uri) {
343 throw new RuntimeException("Not supported");
344 }
345
346 @Override
347 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
348 String sortOrder) {
Grace Jia1ca70d02020-01-16 14:13:12 -0800349 if (!isPathPrefixMatch(uri, CONTENT_URI)) {
SongFerngWang1bb5a6f2019-12-10 00:42:54 +0800350 throw new IllegalArgumentException("Invalid URI: " + uri);
351 } else {
352 // Parse the subId
353 int subId = 0;
354 try {
355 subId = Integer.parseInt(uri.getLastPathSegment());
356 } catch (NumberFormatException e) {
357 Log.d(TAG, "query: no subId provided in uri, using default.");
358 subId = getDefaultSubId();
359 }
360 Log.d(TAG, "subId=" + subId);
361
362 // handle DEFAULT_SUBSCRIPTION_ID
363 if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
364 subId = getDefaultSubId();
365 }
366
367 // Get the service state
368 ServiceState ss = getServiceState(subId);
369 if (ss == null) {
370 Log.d(TAG, "returning null");
371 return null;
372 }
373
374 // Build the result
SongFerngWangf379b8b2019-12-23 18:24:44 +0800375 final int voice_reg_state = ss.getState();
376 final int data_reg_state = ss.getDataRegistrationState();
SongFerngWang1bb5a6f2019-12-10 00:42:54 +0800377 final int voice_roaming_type = ss.getVoiceRoamingType();
378 final int data_roaming_type = ss.getDataRoamingType();
379 final String voice_operator_alpha_long = ss.getOperatorAlphaLong();
380 final String voice_operator_alpha_short = ss.getOperatorAlphaShort();
381 final String voice_operator_numeric = ss.getOperatorNumeric();
382 final String data_operator_alpha_long = ss.getOperatorAlphaLong();
383 final String data_operator_alpha_short = ss.getOperatorAlphaShort();
384 final String data_operator_numeric = ss.getOperatorNumeric();
385 final int is_manual_network_selection = (ss.getIsManualSelection()) ? 1 : 0;
386 final int ril_voice_radio_technology = ss.getRilVoiceRadioTechnology();
387 final int ril_data_radio_technology = ss.getRilDataRadioTechnology();
388 final int css_indicator = ss.getCssIndicator();
389 final int network_id = ss.getCdmaNetworkId();
390 final int system_id = ss.getCdmaSystemId();
391 final int cdma_roaming_indicator = ss.getCdmaRoamingIndicator();
392 final int cdma_default_roaming_indicator = ss.getCdmaDefaultRoamingIndicator();
393 final int cdma_eri_icon_index = ss.getCdmaEriIconIndex();
394 final int cdma_eri_icon_mode = ss.getCdmaEriIconMode();
395 final int is_emergency_only = (ss.isEmergencyOnly()) ? 1 : 0;
396 final int is_using_carrier_aggregation = (ss.isUsingCarrierAggregation()) ? 1 : 0;
397 final String operator_alpha_long_raw = ss.getOperatorAlphaLongRaw();
398 final String operator_alpha_short_raw = ss.getOperatorAlphaShortRaw();
Rambo Wangfbdb3482021-03-15 21:14:19 -0700399 final int data_network_type = ss.getDataNetworkType();
Rambo Wang917ee2f2021-03-15 12:15:51 -0700400 final int duplex_mode = ss.getDuplexMode();
SongFerngWang1bb5a6f2019-12-10 00:42:54 +0800401
402 return buildSingleRowResult(projection, sColumns, new Object[] {
403 voice_reg_state,
404 data_reg_state,
405 voice_roaming_type,
406 data_roaming_type,
407 voice_operator_alpha_long,
408 voice_operator_alpha_short,
409 voice_operator_numeric,
410 data_operator_alpha_long,
411 data_operator_alpha_short,
412 data_operator_numeric,
413 is_manual_network_selection,
414 ril_voice_radio_technology,
415 ril_data_radio_technology,
416 css_indicator,
417 network_id,
418 system_id,
419 cdma_roaming_indicator,
420 cdma_default_roaming_indicator,
421 cdma_eri_icon_index,
422 cdma_eri_icon_mode,
423 is_emergency_only,
424 is_using_carrier_aggregation,
425 operator_alpha_long_raw,
426 operator_alpha_short_raw,
Rambo Wangfbdb3482021-03-15 21:14:19 -0700427 data_network_type,
Rambo Wang917ee2f2021-03-15 12:15:51 -0700428 duplex_mode,
SongFerngWang1bb5a6f2019-12-10 00:42:54 +0800429 });
430 }
431 }
432
433 private static Cursor buildSingleRowResult(String[] projection, String[] availableColumns,
434 Object[] data) {
435 if (projection == null) {
436 projection = availableColumns;
437 }
438 final MatrixCursor c = new MatrixCursor(projection, 1);
439 final RowBuilder row = c.newRow();
440 for (int i = 0; i < c.getColumnCount(); i++) {
441 final String columnName = c.getColumnName(i);
442 boolean found = false;
443 for (int j = 0; j < availableColumns.length; j++) {
444 if (availableColumns[j].equals(columnName)) {
445 row.add(data[j]);
446 found = true;
447 break;
448 }
449 }
450 if (!found) {
451 throw new IllegalArgumentException("Invalid column " + projection[i]);
452 }
453 }
454 return c;
455 }
456
457 /**
458 * Notify interested apps that certain fields of the ServiceState have changed.
459 *
460 * Apps which want to wake when specific fields change can use
461 * JobScheduler's TriggerContentUri. This replaces the waking functionality of the implicit
462 * broadcast of ACTION_SERVICE_STATE_CHANGED for apps targeting version O.
463 *
464 * We will only notify for certain fields. This is an intentional change from the behavior of
465 * the broadcast. Listeners will be notified when the voice or data registration state or
466 * roaming type changes.
467 */
468 @VisibleForTesting
469 public static void notifyChangeForSubIdAndField(Context context, ServiceState oldSS,
470 ServiceState newSS, int subId) {
471 final boolean firstUpdate = (oldSS == null) ? true : false;
472
473 // for every field, if the field has changed values, notify via the provider
474 if (firstUpdate || voiceRegStateChanged(oldSS, newSS)) {
475 context.getContentResolver().notifyChange(
476 getUriForSubscriptionIdAndField(subId, VOICE_REG_STATE),
477 /* observer= */ null, /* syncToNetwork= */ false);
478 }
479 if (firstUpdate || dataRegStateChanged(oldSS, newSS)) {
480 context.getContentResolver().notifyChange(
481 getUriForSubscriptionIdAndField(subId, DATA_REG_STATE), null, false);
482 }
483 if (firstUpdate || voiceRoamingTypeChanged(oldSS, newSS)) {
484 context.getContentResolver().notifyChange(
485 getUriForSubscriptionIdAndField(subId, VOICE_ROAMING_TYPE), null, false);
486 }
487 if (firstUpdate || dataRoamingTypeChanged(oldSS, newSS)) {
488 context.getContentResolver().notifyChange(
489 getUriForSubscriptionIdAndField(subId, DATA_ROAMING_TYPE), null, false);
490 }
Rambo Wangfbdb3482021-03-15 21:14:19 -0700491 if (firstUpdate || dataNetworkTypeChanged(oldSS, newSS)) {
492 context.getContentResolver().notifyChange(
493 getUriForSubscriptionIdAndField(subId, DATA_NETWORK_TYPE), null, false);
494 }
SongFerngWang1bb5a6f2019-12-10 00:42:54 +0800495 }
496
497 private static boolean voiceRegStateChanged(ServiceState oldSS, ServiceState newSS) {
SongFerngWangf379b8b2019-12-23 18:24:44 +0800498 return oldSS.getState() != newSS.getState();
SongFerngWang1bb5a6f2019-12-10 00:42:54 +0800499 }
500
501 private static boolean dataRegStateChanged(ServiceState oldSS, ServiceState newSS) {
SongFerngWangf379b8b2019-12-23 18:24:44 +0800502 return oldSS.getDataRegistrationState() != newSS.getDataRegistrationState();
SongFerngWang1bb5a6f2019-12-10 00:42:54 +0800503 }
504
505 private static boolean voiceRoamingTypeChanged(ServiceState oldSS, ServiceState newSS) {
506 return oldSS.getVoiceRoamingType() != newSS.getVoiceRoamingType();
507 }
508
509 private static boolean dataRoamingTypeChanged(ServiceState oldSS, ServiceState newSS) {
510 return oldSS.getDataRoamingType() != newSS.getDataRoamingType();
511 }
512
Rambo Wangfbdb3482021-03-15 21:14:19 -0700513 private static boolean dataNetworkTypeChanged(ServiceState oldSS, ServiceState newSS) {
514 return oldSS.getDataNetworkType() != newSS.getDataNetworkType();
515 }
516
SongFerngWang1bb5a6f2019-12-10 00:42:54 +0800517 /**
518 * Notify interested apps that the ServiceState has changed.
519 *
520 * Apps which want to wake when any field in the ServiceState has changed can use
521 * JobScheduler's TriggerContentUri. This replaces the waking functionality of the implicit
522 * broadcast of ACTION_SERVICE_STATE_CHANGED for apps targeting version O.
523 *
524 * We will only notify for certain fields. This is an intentional change from the behavior of
525 * the broadcast. Listeners will only be notified when the voice/data registration state or
526 * roaming type changes.
527 */
528 @VisibleForTesting
529 public static void notifyChangeForSubId(Context context, ServiceState oldSS, ServiceState newSS,
530 int subId) {
531 // if the voice or data registration or roaming state field has changed values, notify via
532 // the provider.
533 // If oldSS is null and newSS is not (e.g. first update of service state) this will also
534 // notify
535 if (oldSS == null || voiceRegStateChanged(oldSS, newSS) || dataRegStateChanged(oldSS, newSS)
Rambo Wangfbdb3482021-03-15 21:14:19 -0700536 || voiceRoamingTypeChanged(oldSS, newSS) || dataRoamingTypeChanged(oldSS, newSS)
537 || dataNetworkTypeChanged(oldSS, newSS)) {
SongFerngWang1bb5a6f2019-12-10 00:42:54 +0800538 context.getContentResolver().notifyChange(getUriForSubscriptionId(subId), null, false);
539 }
540 }
Grace Jia1ca70d02020-01-16 14:13:12 -0800541
542 /**
543 * Test if this is a path prefix match against the given Uri. Verifies that
544 * scheme, authority, and atomic path segments match.
545 *
546 * Copied from frameworks/base/core/java/android/net/Uri.java
547 */
548 private boolean isPathPrefixMatch(Uri uriA, Uri uriB) {
549 if (!Objects.equals(uriA.getScheme(), uriB.getScheme())) return false;
550 if (!Objects.equals(uriA.getAuthority(), uriB.getAuthority())) return false;
551
552 List<String> segA = uriA.getPathSegments();
553 List<String> segB = uriB.getPathSegments();
554
555 final int size = segB.size();
556 if (segA.size() < size) return false;
557
558 for (int i = 0; i < size; i++) {
559 if (!Objects.equals(segA.get(i), segB.get(i))) {
560 return false;
561 }
562 }
563
564 return true;
565 }
Grace Jiadd25f0e2020-01-21 12:35:28 -0800566
567 /**
568 * Used to insert a ServiceState into the ServiceStateProvider as a ContentValues instance.
569 *
570 * @param state the ServiceState to convert into ContentValues
571 * @return the convertedContentValues instance
572 * @hide
573 */
574 public static ContentValues getContentValuesForServiceState(ServiceState state) {
575 ContentValues values = new ContentValues();
576 final Parcel p = Parcel.obtain();
577 state.writeToParcel(p, 0);
578 // Turn the parcel to byte array. Safe to do this because the content values were never
579 // written into a persistent storage. ServiceStateProvider keeps values in the memory.
580 values.put(SERVICE_STATE, p.marshall());
581 return values;
582 }
SongFerngWang1bb5a6f2019-12-10 00:42:54 +0800583}