1 /*
2  * Copyright (C) 2022 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 android.app.admin;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.RequiresPermission;
22 import android.annotation.SuppressLint;
23 import android.annotation.SystemApi;
24 import android.content.Context;
25 import android.content.res.Resources;
26 import android.graphics.drawable.Drawable;
27 import android.graphics.drawable.Icon;
28 import android.os.RemoteException;
29 import android.provider.DeviceConfig;
30 import android.util.DisplayMetrics;
31 import android.util.Log;
32 
33 import java.util.ArrayList;
34 import java.util.Objects;
35 import java.util.Set;
36 import java.util.function.Supplier;
37 
38 /**
39  * Class containing required APIs to set, reset, and get device policy related resources.
40  */
41 public class DevicePolicyResourcesManager {
42     private static String TAG = "DevicePolicyResourcesManager";
43 
44     private static String DISABLE_RESOURCES_UPDATABILITY_FLAG = "disable_resources_updatability";
45     private static boolean DEFAULT_DISABLE_RESOURCES_UPDATABILITY = false;
46 
47     private final Context mContext;
48     private final IDevicePolicyManager mService;
49 
50     /**
51      * @hide
52      */
DevicePolicyResourcesManager(Context context, IDevicePolicyManager service)53     protected DevicePolicyResourcesManager(Context context, IDevicePolicyManager service) {
54         mContext = context;
55         mService = service;
56     }
57 
58     /**
59      * For each {@link DevicePolicyDrawableResource} item in {@code drawables}, if
60      * {@link DevicePolicyDrawableResource#getDrawableSource()} is not set, it updates the drawable
61      * resource for the combination of {@link DevicePolicyDrawableResource#getDrawableId()} and
62      * {@link DevicePolicyDrawableResource#getDrawableStyle()} to the drawable with resource ID
63      * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()},
64      * meaning any system UI surface calling {@link #getDrawable} with {@code drawableId} and
65      * {@code drawableStyle} will get the new resource after this API is called.
66      *
67      * <p>Otherwise, if {@link DevicePolicyDrawableResource#getDrawableSource()} is set, it
68      * overrides any drawables that was set for the same {@code drawableId} and
69      * {@code drawableStyle} for the provided source.
70      *
71      * <p>Sends a broadcast with action
72      * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to registered receivers
73      * when a resource has been updated successfully.
74      *
75      * <p>Important notes to consider when using this API:
76      * <ul>
77      * <li> Updated resources are persisted over reboots.
78      * <li>{@link #getDrawable} references the resource
79      * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()} in the
80      * calling package each time it gets called. You have to ensure that the resource is always
81      * available in the calling package as long as it is used as an updated resource.
82      * <li>You still have to re-call {@code setDrawables} even if you only make changes to the
83      * content of the resource with ID
84      * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()} as the content might be
85      * cached and would need updating.
86      * </ul>
87      *
88      * @param drawables The list of {@link DevicePolicyDrawableResource} to update.
89      *
90      * @hide
91      */
92     @SystemApi
93     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
setDrawables(@onNull Set<DevicePolicyDrawableResource> drawables)94     public void setDrawables(@NonNull Set<DevicePolicyDrawableResource> drawables) {
95         if (mService != null) {
96             try {
97                 mService.setDrawables(new ArrayList<>(drawables));
98             } catch (RemoteException e) {
99                 throw e.rethrowFromSystemServer();
100             }
101         }
102     }
103 
104     /**
105      * Removes all updated drawables for the list of {@code drawableIds} that was previously set by
106      * calling {@link #setDrawables}, meaning any subsequent calls to {@link #getDrawable} for the
107      * provided IDs with any {@code drawableStyle} and any {@code drawableSource} will return the
108      * default drawable from {@code defaultDrawableLoader}.
109      *
110      * <p>Sends a broadcast with action
111      * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to registered receivers
112      * when a resource has been reset successfully.
113      *
114      * @param drawableIds The list of IDs to remove.
115      *
116      * @hide
117      */
118     @SystemApi
119     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
resetDrawables(@onNull Set<String> drawableIds)120     public void resetDrawables(@NonNull Set<String> drawableIds) {
121         if (mService != null) {
122             try {
123                 mService.resetDrawables(new ArrayList<>(drawableIds));
124             } catch (RemoteException e) {
125                 throw e.rethrowFromSystemServer();
126             }
127         }
128     }
129 
130     /**
131      * Returns the appropriate updated drawable for the {@code drawableId} with style
132      * {@code drawableStyle} if one was set using {@code setDrawables}, otherwise returns the
133      * drawable from {@code defaultDrawableLoader}.
134      *
135      * <p>Also returns the drawable from {@code defaultDrawableLoader} if {@code drawableId}
136      * is {@link DevicePolicyResources#UNDEFINED}.
137      *
138      * <p>Calls to this API will not return {@code null} unless no updated drawable was found
139      * and the call to {@code defaultDrawableLoader} returned {@code null}.
140      *
141      * <p>This API uses the screen density returned from {@link Resources#getConfiguration()}, to
142      * set a different value use
143      * {@link #getDrawableForDensity(String, String, int, Supplier)}.
144      *
145      * <p>Callers should register for
146      * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
147      * resource has been updated.
148      *
149      * <p>Note that each call to this API loads the resource from the package that called
150      * {@code setDrawables} to set the updated resource.
151      *
152      * @param drawableId The drawable ID to get the updated resource for.
153      * @param drawableStyle The drawable style to use.
154      * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
155      *                              the provided params.
156      */
157     @Nullable
getDrawable( @onNull String drawableId, @NonNull String drawableStyle, @NonNull Supplier<Drawable> defaultDrawableLoader)158     public Drawable getDrawable(
159             @NonNull String drawableId,
160             @NonNull String drawableStyle,
161             @NonNull Supplier<Drawable> defaultDrawableLoader) {
162         return getDrawable(
163                 drawableId, drawableStyle, DevicePolicyResources.UNDEFINED, defaultDrawableLoader);
164     }
165 
166     /**
167      * Similar to {@link #getDrawable(String, String, Supplier)}, but also accepts
168      * a {@code drawableSource} which could result in returning a different drawable than
169      * {@link #getDrawable(String, String, Supplier)} if an override was set for that specific
170      * source.
171      *
172      * <p> If {@code drawableSource} is {@link DevicePolicyResources#UNDEFINED}, it returns the
173      * appropriate string for {@code drawableId} and {@code drawableStyle} similar to
174      * {@link #getDrawable(String, String, Supplier)}.
175      *
176      * <p>Calls to this API will not return {@code null} unless no updated drawable was found
177      * and the call to {@code defaultDrawableLoader} returned {@code null}.
178      *
179      * <p>Callers should register for
180      * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
181      * resource has been updated.
182      *
183      * @param drawableId The drawable ID to get the updated resource for.
184      * @param drawableStyle The drawable style to use.
185      * @param drawableSource The source for the caller.
186      * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
187      *                              the provided params.
188      */
189     @Nullable
getDrawable( @onNull String drawableId, @NonNull String drawableStyle, @NonNull String drawableSource, @NonNull Supplier<Drawable> defaultDrawableLoader)190     public Drawable getDrawable(
191             @NonNull String drawableId,
192             @NonNull String drawableStyle,
193             @NonNull String drawableSource,
194             @NonNull Supplier<Drawable> defaultDrawableLoader) {
195 
196         Objects.requireNonNull(drawableId, "drawableId can't be null");
197         Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
198         Objects.requireNonNull(drawableSource, "drawableSource can't be null");
199         Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
200 
201         if (drawableId.equals(DevicePolicyResources.UNDEFINED)
202                 || DeviceConfig.getBoolean(
203                         DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
204                         DISABLE_RESOURCES_UPDATABILITY_FLAG,
205                         DEFAULT_DISABLE_RESOURCES_UPDATABILITY)) {
206             return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
207         }
208 
209         if (mService != null) {
210             try {
211                 ParcelableResource resource = mService.getDrawable(
212                         drawableId, drawableStyle, drawableSource);
213                 if (resource == null) {
214                     return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
215                 }
216                 return resource.getDrawable(
217                         mContext,
218                         /* density= */ 0,
219                         defaultDrawableLoader);
220 
221             } catch (RemoteException e) {
222                 Log.e(
223                         TAG,
224                         "Error getting the updated drawable from DevicePolicyManagerService.",
225                         e);
226                 return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
227             }
228         }
229         return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
230     }
231 
232     /**
233      * Similar to {@link #getDrawable(String, String, Supplier)}, but also accepts
234      * {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
235      *
236      * <p>Calls to this API will not return {@code null} unless no updated drawable was found
237      * and the call to {@code defaultDrawableLoader} returned {@code null}.
238      *
239      * <p>Callers should register for
240      * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
241      * resource has been updated.
242      *
243      * @param drawableId The drawable ID to get the updated resource for.
244      * @param drawableStyle The drawable style to use.
245      * @param density The desired screen density indicated by the resource as
246      *            found in {@link DisplayMetrics}. A value of 0 means to use the
247      *            density returned from {@link Resources#getConfiguration()}.
248      * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
249      *                              the provided params.
250      */
251     @Nullable
getDrawableForDensity( @onNull String drawableId, @NonNull String drawableStyle, int density, @NonNull Supplier<Drawable> defaultDrawableLoader)252     public Drawable getDrawableForDensity(
253             @NonNull String drawableId,
254             @NonNull String drawableStyle,
255             int density,
256             @NonNull Supplier<Drawable> defaultDrawableLoader) {
257         return getDrawableForDensity(
258                 drawableId,
259                 drawableStyle,
260                 DevicePolicyResources.UNDEFINED,
261                 density,
262                 defaultDrawableLoader);
263     }
264 
265     /**
266      * Similar to {@link #getDrawable(String, String, String, Supplier)}, but also accepts
267      * {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
268      *
269      * <p>Calls to this API will not return {@code null} unless no updated drawable was found
270      * and the call to {@code defaultDrawableLoader} returned {@code null}.
271      *
272      * <p>Callers should register for
273      * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
274      * resource has been updated.
275      *
276      * @param drawableId The drawable ID to get the updated resource for.
277      * @param drawableStyle The drawable style to use.
278      * @param drawableSource The source for the caller.
279      * @param density The desired screen density indicated by the resource as
280      *            found in {@link DisplayMetrics}. A value of 0 means to use the
281      *            density returned from {@link Resources#getConfiguration()}.
282      * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
283      *                              the provided params.
284      */
285     @Nullable
getDrawableForDensity( @onNull String drawableId, @NonNull String drawableStyle, @NonNull String drawableSource, int density, @NonNull Supplier<Drawable> defaultDrawableLoader)286     public Drawable getDrawableForDensity(
287             @NonNull String drawableId,
288             @NonNull String drawableStyle,
289             @NonNull String drawableSource,
290             int density,
291             @NonNull Supplier<Drawable> defaultDrawableLoader) {
292 
293         Objects.requireNonNull(drawableId, "drawableId can't be null");
294         Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
295         Objects.requireNonNull(drawableSource, "drawableSource can't be null");
296         Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
297 
298         if (drawableId.equals(DevicePolicyResources.UNDEFINED)
299                 || DeviceConfig.getBoolean(
300                         DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
301                         DISABLE_RESOURCES_UPDATABILITY_FLAG,
302                         DEFAULT_DISABLE_RESOURCES_UPDATABILITY)) {
303             return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
304         }
305 
306         if (mService != null) {
307             try {
308                 ParcelableResource resource = mService.getDrawable(
309                         drawableId, drawableStyle, drawableSource);
310                 if (resource == null) {
311                     return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
312                 }
313                 return resource.getDrawable(mContext, density, defaultDrawableLoader);
314             } catch (RemoteException e) {
315                 Log.e(
316                         TAG,
317                         "Error getting the updated drawable from DevicePolicyManagerService.",
318                         e);
319                 return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
320             }
321         }
322         return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
323     }
324 
325     /**
326      * Similar to {@link #getDrawable(String, String, String, Supplier)} but returns an
327      * {@link Icon} instead of a {@link Drawable}.
328      *
329      * @param drawableId The drawable ID to get the updated resource for.
330      * @param drawableStyle The drawable style to use.
331      * @param drawableSource The source for the caller.
332      * @param defaultIcon Returned if no updated drawable was set for the provided params.
333      */
334     @Nullable
getDrawableAsIcon( @onNull String drawableId, @NonNull String drawableStyle, @NonNull String drawableSource, @Nullable Icon defaultIcon)335     public Icon getDrawableAsIcon(
336             @NonNull String drawableId,
337             @NonNull String drawableStyle,
338             @NonNull String drawableSource,
339             @Nullable Icon defaultIcon) {
340         Objects.requireNonNull(drawableId, "drawableId can't be null");
341         Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
342         Objects.requireNonNull(drawableSource, "drawableSource can't be null");
343         Objects.requireNonNull(defaultIcon, "defaultIcon can't be null");
344 
345         if (drawableId.equals(DevicePolicyResources.UNDEFINED)
346                 || DeviceConfig.getBoolean(
347                         DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
348                         DISABLE_RESOURCES_UPDATABILITY_FLAG,
349                         DEFAULT_DISABLE_RESOURCES_UPDATABILITY)) {
350             return defaultIcon;
351         }
352 
353         if (mService != null) {
354             try {
355                 ParcelableResource resource = mService.getDrawable(
356                         drawableId, drawableStyle, drawableSource);
357                 if (resource == null) {
358                     return defaultIcon;
359                 }
360                 return Icon.createWithResource(resource.getPackageName(), resource.getResourceId());
361             } catch (RemoteException e) {
362                 Log.e(
363                         TAG,
364                         "Error getting the updated drawable from DevicePolicyManagerService.",
365                         e);
366                 return defaultIcon;
367             }
368         }
369         return defaultIcon;
370     }
371 
372     /**
373      * Similar to {@link #getDrawable(String, String, Supplier)} but returns an {@link Icon}
374      * instead of a {@link Drawable}.
375      *
376      * @param drawableId The drawable ID to get the updated resource for.
377      * @param drawableStyle The drawable style to use.
378      * @param defaultIcon Returned if no updated drawable was set for the provided params.
379      */
380     @Nullable
getDrawableAsIcon( @onNull String drawableId, @NonNull String drawableStyle, @Nullable Icon defaultIcon)381     public Icon getDrawableAsIcon(
382             @NonNull String drawableId,
383             @NonNull String drawableStyle,
384             @Nullable Icon defaultIcon) {
385         return getDrawableAsIcon(
386                 drawableId, drawableStyle, DevicePolicyResources.UNDEFINED, defaultIcon);
387     }
388 
389 
390     /**
391      * For each {@link DevicePolicyStringResource} item in {@code strings}, it updates the string
392      * resource for {@link DevicePolicyStringResource#getStringId()} to the string with ID
393      * {@code callingPackageResourceId}, meaning any system UI surface calling {@link #getString}
394      * with {@code stringId} will get the new resource after this API is called.
395      *
396      * <p>Sends a broadcast with action
397      * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to registered receivers
398      * when a resource has been updated successfully.
399      *
400      * <p>Important notes to consider when using this API:
401      * <ul>
402      * <li> Updated resources are persisted over reboots.
403      * <li> {@link #getString} references the resource
404      * {@link DevicePolicyStringResource#getResourceIdInCallingPackage()} in the
405      * calling package each time it gets called. You have to ensure that the resource is always
406      * available in the calling package as long as it is used as an updated resource.
407      * <li> You still have to re-call {@code setStrings} even if you only make changes to the
408      * content of the resource with ID {@code callingPackageResourceId} as the content might be
409      * cached and would need updating.
410      * </ul>
411      *
412      * @param strings The list of {@link DevicePolicyStringResource} to update.
413      *
414      * @hide
415      */
416     @SystemApi
417     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
setStrings(@onNull Set<DevicePolicyStringResource> strings)418     public void setStrings(@NonNull Set<DevicePolicyStringResource> strings) {
419         if (mService != null) {
420             try {
421                 mService.setStrings(new ArrayList<>(strings));
422             } catch (RemoteException e) {
423                 throw e.rethrowFromSystemServer();
424             }
425         }
426     }
427 
428     /**
429      * Removes the updated strings for the list of {@code stringIds} that was previously set by
430      * calling {@link #setStrings}, meaning any subsequent calls to {@link #getString} for the
431      * provided IDs will return the default string from {@code defaultStringLoader}.
432      *
433      * <p>Sends a broadcast with action
434      * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to registered receivers
435      * when a resource has been reset successfully.
436      *
437      * @param stringIds The list of IDs to remove the updated resources for.
438      *
439      * @hide
440      */
441     @SystemApi
442     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
resetStrings(@onNull Set<String> stringIds)443     public void resetStrings(@NonNull Set<String> stringIds) {
444         if (mService != null) {
445             try {
446                 mService.resetStrings(new ArrayList<>(stringIds));
447             } catch (RemoteException e) {
448                 throw e.rethrowFromSystemServer();
449             }
450         }
451     }
452 
453     /**
454      * Returns the appropriate updated string for the {@code stringId} (see
455      * {@code DevicePolicyResources.Strings}) if one was set using
456      * {@code setStrings}, otherwise returns the string from {@code defaultStringLoader}.
457      *
458      * <p>Also returns the string from {@code defaultStringLoader} if {@code stringId} is
459      * {@link DevicePolicyResources#UNDEFINED}.
460      *
461      * <p>Calls to this API will not return {@code null} unless no updated drawable was found
462      * and the call to {@code defaultStringLoader} returned {@code null}.
463      *
464      * <p>Callers should register for
465      * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
466      * resource has been updated.
467      *
468      * <p>Note that each call to this API loads the resource from the package that called
469      * {@code setStrings} to set the updated resource.
470      *
471      * @param stringId The IDs to get the updated resource for.
472      * @param defaultStringLoader To get the default string if no updated string was set for
473      *         {@code stringId}.
474      */
475     @Nullable
getString( @onNull String stringId, @NonNull Supplier<String> defaultStringLoader)476     public String getString(
477             @NonNull String stringId,
478             @NonNull Supplier<String> defaultStringLoader) {
479 
480         Objects.requireNonNull(stringId, "stringId can't be null");
481         Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
482 
483         if (stringId.equals(DevicePolicyResources.UNDEFINED) || DeviceConfig.getBoolean(
484                 DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
485                 DISABLE_RESOURCES_UPDATABILITY_FLAG,
486                 DEFAULT_DISABLE_RESOURCES_UPDATABILITY)) {
487             return ParcelableResource.loadDefaultString(defaultStringLoader);
488         }
489         if (mService != null) {
490             try {
491                 ParcelableResource resource = mService.getString(stringId);
492                 if (resource == null) {
493                     return ParcelableResource.loadDefaultString(defaultStringLoader);
494                 }
495                 return resource.getString(mContext, defaultStringLoader);
496             } catch (RemoteException e) {
497                 Log.e(
498                         TAG,
499                         "Error getting the updated string from DevicePolicyManagerService.",
500                         e);
501                 return ParcelableResource.loadDefaultString(defaultStringLoader);
502             }
503         }
504         return ParcelableResource.loadDefaultString(defaultStringLoader);
505     }
506 
507     /**
508      * Similar to {@link #getString(String, Supplier)} but accepts {@code formatArgs} and returns a
509      * localized formatted string, substituting the format arguments as defined in
510      * {@link java.util.Formatter} and {@link java.lang.String#format}, (see
511      * {@link Resources#getString(int, Object...)}).
512      *
513      * <p>Calls to this API will not return {@code null} unless no updated drawable was found
514      * and the call to {@code defaultStringLoader} returned {@code null}.
515      *
516      * @param stringId The IDs to get the updated resource for.
517      * @param defaultStringLoader To get the default string if no updated string was set for
518      *         {@code stringId}.
519      * @param formatArgs The format arguments that will be used for substitution.
520      */
521     @Nullable
522     @SuppressLint("SamShouldBeLast")
getString( @onNull String stringId, @NonNull Supplier<String> defaultStringLoader, @NonNull Object... formatArgs)523     public String getString(
524             @NonNull String stringId,
525             @NonNull Supplier<String> defaultStringLoader,
526             @NonNull Object... formatArgs) {
527 
528         Objects.requireNonNull(stringId, "stringId can't be null");
529         Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
530 
531         if (stringId.equals(DevicePolicyResources.UNDEFINED) || DeviceConfig.getBoolean(
532                 DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
533                 DISABLE_RESOURCES_UPDATABILITY_FLAG,
534                 DEFAULT_DISABLE_RESOURCES_UPDATABILITY)) {
535             return ParcelableResource.loadDefaultString(defaultStringLoader);
536         }
537         if (mService != null) {
538             try {
539                 ParcelableResource resource = mService.getString(stringId);
540                 if (resource == null) {
541                     return ParcelableResource.loadDefaultString(defaultStringLoader);
542                 }
543                 return resource.getString(mContext, defaultStringLoader, formatArgs);
544             } catch (RemoteException e) {
545                 Log.e(
546                         TAG,
547                         "Error getting the updated string from DevicePolicyManagerService.",
548                         e);
549                 return ParcelableResource.loadDefaultString(defaultStringLoader);
550             }
551         }
552         return ParcelableResource.loadDefaultString(defaultStringLoader);
553     }
554 }
555