• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.google.android.setupcompat.internal;
18 
19 import android.annotation.TargetApi;
20 import android.os.BaseBundle;
21 import android.os.Build.VERSION_CODES;
22 import android.os.Bundle;
23 import android.os.PersistableBundle;
24 import android.util.ArrayMap;
25 import android.util.Log;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collections;
29 import java.util.List;
30 
31 /** Contains utility methods related to {@link PersistableBundle}. */
32 @TargetApi(VERSION_CODES.Q)
33 public final class PersistableBundles {
34 
35   /**
36    * Merges two or more {@link PersistableBundle}. Ensures no conflict of keys occurred during
37    * merge.
38    *
39    * @return Returns a new {@link PersistableBundle} that contains all the data from {@code
40    *     firstBundle}, {@code nextBundle} and {@code others}.
41    */
mergeBundles( PersistableBundle firstBundle, PersistableBundle nextBundle, PersistableBundle... others)42   public static PersistableBundle mergeBundles(
43       PersistableBundle firstBundle, PersistableBundle nextBundle, PersistableBundle... others) {
44     List<PersistableBundle> allBundles = new ArrayList<>();
45     allBundles.addAll(Arrays.asList(firstBundle, nextBundle));
46     Collections.addAll(allBundles, others);
47 
48     PersistableBundle result = new PersistableBundle();
49     for (PersistableBundle bundle : allBundles) {
50       for (String key : bundle.keySet()) {
51         Preconditions.checkArgument(
52             !result.containsKey(key),
53             String.format("Found duplicate key [%s] while attempting to merge bundles.", key));
54       }
55       result.putAll(bundle);
56     }
57 
58     return result;
59   }
60 
61   /** Returns a {@link Bundle} that contains all the values from {@code persistableBundle}. */
toBundle(PersistableBundle persistableBundle)62   public static Bundle toBundle(PersistableBundle persistableBundle) {
63     Bundle bundle = new Bundle();
64     bundle.putAll(persistableBundle);
65     return bundle;
66   }
67 
68   /**
69    * Returns a {@link PersistableBundle} that contains values from {@code bundle} that are supported
70    * by the logging API. Un-supported value types are dropped.
71    */
fromBundle(Bundle bundle)72   public static PersistableBundle fromBundle(Bundle bundle) {
73     PersistableBundle to = new PersistableBundle();
74     ArrayMap<String, Object> map = toMap(bundle);
75     for (String key : map.keySet()) {
76       Object value = map.get(key);
77       if (value instanceof Long) {
78         to.putLong(key, (Long) value);
79       } else if (value instanceof Integer) {
80         to.putInt(key, (Integer) value);
81       } else if (value instanceof Double) {
82         to.putDouble(key, (Double) value);
83       } else if (value instanceof Boolean) {
84         to.putBoolean(key, (Boolean) value);
85       } else if (value instanceof String) {
86         to.putString(key, (String) value);
87       } else {
88         throw new AssertionError(String.format("Missing put* for valid data type? = %s", value));
89       }
90     }
91     return to;
92   }
93 
94   /** Returns {@code true} if {@code left} contains same set of values as {@code right}. */
equals(PersistableBundle left, PersistableBundle right)95   public static boolean equals(PersistableBundle left, PersistableBundle right) {
96     return (left == right) || toMap(left).equals(toMap(right));
97   }
98 
99   /** Asserts that {@code persistableBundle} contains only supported data types. */
assertIsValid(PersistableBundle persistableBundle)100   public static PersistableBundle assertIsValid(PersistableBundle persistableBundle) {
101     Preconditions.checkNotNull(persistableBundle, "PersistableBundle cannot be null!");
102     for (String key : persistableBundle.keySet()) {
103       Object value = persistableBundle.get(key);
104       Preconditions.checkArgument(
105           isSupportedDataType(value),
106           String.format("Unknown/unsupported data type [%s] for key %s", value, key));
107     }
108     return persistableBundle;
109   }
110 
111   /**
112    * Returns a new {@link ArrayMap} that contains values from {@code bundle} that are supported by
113    * the logging API.
114    */
toMap(BaseBundle baseBundle)115   private static ArrayMap<String, Object> toMap(BaseBundle baseBundle) {
116     if (baseBundle == null || baseBundle.isEmpty()) {
117       return new ArrayMap<>(0);
118     }
119 
120     ArrayMap<String, Object> map = new ArrayMap<>(baseBundle.size());
121     for (String key : baseBundle.keySet()) {
122       Object value = baseBundle.get(key);
123       if (!isSupportedDataType(value)) {
124         Log.w(TAG, String.format("Unknown/unsupported data type [%s] for key %s", value, key));
125         continue;
126       }
127       map.put(key, baseBundle.get(key));
128     }
129     return map;
130   }
131 
isSupportedDataType(Object value)132   private static boolean isSupportedDataType(Object value) {
133     return value instanceof Integer
134         || value instanceof Long
135         || value instanceof Double
136         || value instanceof Float
137         || value instanceof String
138         || value instanceof Boolean;
139   }
140 
PersistableBundles()141   private PersistableBundles() {
142     throw new AssertionError("Should not be instantiated");
143   }
144 
145   private static final String TAG = "SetupCompat.PersistBls";
146 }
147