1d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam/* 2d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * Copyright (C) 2015 The Android Open Source Project 3d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * 4d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * Licensed under the Apache License, Version 2.0 (the "License"); 5d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * you may not use this file except in compliance with the License. 6d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * You may obtain a copy of the License at 7d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * 8d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * http://www.apache.org/licenses/LICENSE-2.0 9d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * 10d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * Unless required by applicable law or agreed to in writing, software 11d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * distributed under the License is distributed on an "AS IS" BASIS, 12d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * See the License for the specific language governing permissions and 14d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * limitations under the License. 15d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam */ 16d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 17d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lampackage com.android.setupwizardlib.util; 18d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 19d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lamimport android.content.Context; 20d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lamimport android.content.Intent; 21d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lamimport android.content.pm.ApplicationInfo; 22d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lamimport android.content.pm.PackageManager; 23d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lamimport android.content.pm.PackageManager.NameNotFoundException; 24d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lamimport android.content.pm.ResolveInfo; 25d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lamimport android.content.res.Resources; 26d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lamimport android.graphics.drawable.Drawable; 27d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lamimport android.util.Log; 28d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 298c10c403c063aff3f17c4949b0fe9a88536ae580Maurice Lamimport com.android.setupwizardlib.annotations.VisibleForTesting; 30d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 31d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam/** 32d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * Utilities to discover and interact with partner customizations. There can only be one set of 33d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * customizations on a device, and it must be bundled with the system. 34d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * 35d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * Derived from com.android.launcher3/Partner.java 36d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam */ 37d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lampublic class Partner { 38d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam private static final String TAG = "(SUW) Partner"; 39d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 40d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam /** Marker action used to discover partner */ 41d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam private static final String 42d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam ACTION_PARTNER_CUSTOMIZATION = "com.android.setupwizard.action.PARTNER_CUSTOMIZATION"; 43d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 44d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam private static boolean sSearched = false; 45d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam private static Partner sPartner; 46d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 47d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam /** 48d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * Convenience to get a drawable from partner overlay, or if not available, the drawable from 49d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * the original context. 50d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * 51d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * @see #getResourceEntry(android.content.Context, int) 52d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam */ 53d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam public static Drawable getDrawable(Context context, int id) { 54d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam final ResourceEntry entry = getResourceEntry(context, id); 55d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam return entry.resources.getDrawable(entry.id); 56d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 57d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 58d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam /** 59d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * Convenience to get a string from partner overlay, or if not available, the string from the 60d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * original context. 61d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * 62d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * @see #getResourceEntry(android.content.Context, int) 63d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam */ 64d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam public static String getString(Context context, int id) { 65d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam final ResourceEntry entry = getResourceEntry(context, id); 66d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam return entry.resources.getString(entry.id); 67d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 68d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 69d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam /** 70d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * Find an entry of resource in the overlay package provided by partners. It will first look for 71d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * the resource in the overlay package, and if not available, will return the one in the 72d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * original context. 73d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * 74d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * @return a ResourceEntry in the partner overlay's resources, if one is defined. Otherwise the 75d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * resources from the original context is returned. Clients can then get the resource by 76d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * {@code entry.resources.getString(entry.id)}, or other methods available in 77d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * {@link android.content.res.Resources}. 78d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam */ 79d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam public static ResourceEntry getResourceEntry(Context context, int id) { 80d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam final Partner partner = Partner.get(context); 8164158e33c3ad618ed0eecef71fd20dd8e3c02568Maurice Lam if (partner != null) { 82d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam final Resources ourResources = context.getResources(); 83d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam final String name = ourResources.getResourceEntryName(id); 84d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam final String type = ourResources.getResourceTypeName(id); 85d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam final int partnerId = partner.getIdentifier(name, type); 8664158e33c3ad618ed0eecef71fd20dd8e3c02568Maurice Lam if (partnerId != 0) { 8764158e33c3ad618ed0eecef71fd20dd8e3c02568Maurice Lam return new ResourceEntry(partner.mResources, partnerId, true); 8864158e33c3ad618ed0eecef71fd20dd8e3c02568Maurice Lam } 89d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 9064158e33c3ad618ed0eecef71fd20dd8e3c02568Maurice Lam return new ResourceEntry(context.getResources(), id, false); 91d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 92d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 93d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam public static class ResourceEntry { 94d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam public Resources resources; 95d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam public int id; 9664158e33c3ad618ed0eecef71fd20dd8e3c02568Maurice Lam public boolean isOverlay; 97d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 9864158e33c3ad618ed0eecef71fd20dd8e3c02568Maurice Lam ResourceEntry(Resources resources, int id, boolean isOverlay) { 99d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam this.resources = resources; 100d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam this.id = id; 10164158e33c3ad618ed0eecef71fd20dd8e3c02568Maurice Lam this.isOverlay = isOverlay; 102d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 103d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 104d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 105d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam /** 106d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * Find and return partner details, or {@code null} if none exists. A partner package is marked 107d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * by a broadcast receiver declared in the manifest that handles the 108d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * com.android.setupwizard.action.PARTNER_CUSTOMIZATION intent action. The overlay package must 109d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam * also be a system package. 110d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam */ 111d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam public static synchronized Partner get(Context context) { 112d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam if (!sSearched) { 113d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam PackageManager pm = context.getPackageManager(); 114d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam final Intent intent = new Intent(ACTION_PARTNER_CUSTOMIZATION); 115d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam for (ResolveInfo info : pm.queryBroadcastReceivers(intent, 0)) { 116d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam if (info.activityInfo == null) { 117d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam continue; 118d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 119d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam final ApplicationInfo appInfo = info.activityInfo.applicationInfo; 120d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 121d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam try { 122d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam final Resources res = pm.getResourcesForApplication(appInfo); 123d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam sPartner = new Partner(appInfo.packageName, res); 124d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam break; 125d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } catch (NameNotFoundException e) { 126d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam Log.w(TAG, "Failed to find resources for " + appInfo.packageName); 127d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 128d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 129d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 130d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam sSearched = true; 131d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 132d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam return sPartner; 133d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 134d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 135d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam @VisibleForTesting 136d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam public static synchronized void resetForTesting() { 137d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam sSearched = false; 138d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam sPartner = null; 139d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 140d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 141d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam private final String mPackageName; 142d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam private final Resources mResources; 143d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 144d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam private Partner(String packageName, Resources res) { 145d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam mPackageName = packageName; 146d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam mResources = res; 147d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 148d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 149d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam public String getPackageName() { 150d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam return mPackageName; 151d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 152d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 153d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam public Resources getResources() { 154d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam return mResources; 155d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 156d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam 157d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam public int getIdentifier(String name, String defType) { 158d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam return mResources.getIdentifier(name, defType, mPackageName); 159d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam } 160d617ee5e12914b052682ee6f1bdf3ece28392f54Maurice Lam} 161