/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.setupwizardlib.util; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; import android.support.annotation.AnyRes; import android.support.annotation.DrawableRes; import android.support.annotation.StringRes; import android.support.annotation.VisibleForTesting; import android.util.Log; import java.util.List; /** * Utilities to discover and interact with partner customizations. An overlay package is one that * registers the broadcast receiver for {@code com.android.setupwizard.action.PARTNER_CUSTOMIZATION} * in its manifest. There can only be one customization APK on a device, and it must be bundled with * the system. * *
Derived from {@code com.android.launcher3/Partner.java}
*/
public class Partner {
private static final String TAG = "(SUW) Partner";
/** Marker action used to discover partner */
private static final String ACTION_PARTNER_CUSTOMIZATION =
"com.android.setupwizard.action.PARTNER_CUSTOMIZATION";
private static boolean sSearched = false;
private static Partner sPartner;
/**
* Convenience to get a drawable from partner overlay, or if not available, the drawable from
* the original context.
*
* @see #getResourceEntry(android.content.Context, int)
*/
public static Drawable getDrawable(Context context, @DrawableRes int id) {
final ResourceEntry entry = getResourceEntry(context, id);
return entry.resources.getDrawable(entry.id);
}
/**
* Convenience to get a string from partner overlay, or if not available, the string from the
* original context.
*
* @see #getResourceEntry(android.content.Context, int)
*/
public static String getString(Context context, @StringRes int id) {
final ResourceEntry entry = getResourceEntry(context, id);
return entry.resources.getString(entry.id);
}
/**
* Convenience method to get a CharSequence from partner overlay, or if not available, the text
* from the original context.
*/
public static CharSequence getText(Context context, @StringRes int id) {
final ResourceEntry entry = getResourceEntry(context, id);
return entry.resources.getText(id);
}
/**
* Find an entry of resource in the overlay package provided by partners. It will first look for
* the resource in the overlay package, and if not available, will return the one in the
* original context.
*
* @return a ResourceEntry in the partner overlay's resources, if one is defined. Otherwise the
* resources from the original context is returned. Clients can then get the resource by
* {@code entry.resources.getString(entry.id)}, or other methods available in
* {@link android.content.res.Resources}.
*/
public static ResourceEntry getResourceEntry(Context context, @AnyRes int id) {
final Partner partner = Partner.get(context);
if (partner != null) {
final Resources ourResources = context.getResources();
final String name = ourResources.getResourceEntryName(id);
final String type = ourResources.getResourceTypeName(id);
final int partnerId = partner.getIdentifier(name, type);
if (partnerId != 0) {
return new ResourceEntry(partner.mResources, partnerId, true);
}
}
return new ResourceEntry(context.getResources(), id, false);
}
public static class ResourceEntry {
public Resources resources;
public int id;
public boolean isOverlay;
ResourceEntry(Resources resources, int id, boolean isOverlay) {
this.resources = resources;
this.id = id;
this.isOverlay = isOverlay;
}
}
/**
* Find and return partner details, or {@code null} if none exists. A partner package is marked
* by a broadcast receiver declared in the manifest that handles the
* {@code com.android.setupwizard.action.PARTNER_CUSTOMIZATION} intent action. The overlay
* package must also be a system package.
*/
public static synchronized Partner get(Context context) {
if (!sSearched) {
PackageManager pm = context.getPackageManager();
final Intent intent = new Intent(ACTION_PARTNER_CUSTOMIZATION);
List