/* * Copyright (C) 2014 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.systemui.statusbar.policy; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.statusbar.phone.KeyguardPreviewContainer; import java.util.List; /** * Utility class to inflate previews for phone and camera affordance. */ public class PreviewInflater { private static final String TAG = "PreviewInflater"; private static final String META_DATA_KEYGUARD_LAYOUT = "com.android.keyguard.layout"; private Context mContext; private LockPatternUtils mLockPatternUtils; public PreviewInflater(Context context, LockPatternUtils lockPatternUtils) { mContext = context; mLockPatternUtils = lockPatternUtils; } public View inflatePreview(Intent intent) { WidgetInfo info = getWidgetInfo(intent); return inflatePreview(info); } public View inflatePreviewFromService(ComponentName componentName) { WidgetInfo info = getWidgetInfoFromService(componentName); return inflatePreview(info); } private KeyguardPreviewContainer inflatePreview(WidgetInfo info) { if (info == null) { return null; } View v = inflateWidgetView(info); if (v == null) { return null; } KeyguardPreviewContainer container = new KeyguardPreviewContainer(mContext, null); container.addView(v); return container; } private View inflateWidgetView(WidgetInfo widgetInfo) { View widgetView = null; try { Context appContext = mContext.createPackageContext( widgetInfo.contextPackage, Context.CONTEXT_RESTRICTED); LayoutInflater appInflater = (LayoutInflater) appContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); appInflater = appInflater.cloneInContext(appContext); widgetView = appInflater.inflate(widgetInfo.layoutId, null, false); } catch (PackageManager.NameNotFoundException|RuntimeException e) { Log.w(TAG, "Error creating widget view", e); } return widgetView; } private WidgetInfo getWidgetInfoFromService(ComponentName componentName) { PackageManager packageManager = mContext.getPackageManager(); // Look for the preview specified in the service meta-data try { Bundle metaData = packageManager.getServiceInfo( componentName, PackageManager.GET_META_DATA).metaData; return getWidgetInfoFromMetaData(componentName.getPackageName(), metaData); } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Failed to load preview; " + componentName.flattenToShortString() + " not found", e); } return null; } private WidgetInfo getWidgetInfoFromMetaData(String contextPackage, Bundle metaData) { if (metaData == null) { return null; } int layoutId = metaData.getInt(META_DATA_KEYGUARD_LAYOUT); if (layoutId == 0) { return null; } WidgetInfo info = new WidgetInfo(); info.contextPackage = contextPackage; info.layoutId = layoutId; return info; } private WidgetInfo getWidgetInfo(Intent intent) { PackageManager packageManager = mContext.getPackageManager(); int flags = PackageManager.MATCH_DEFAULT_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; final List appList = packageManager.queryIntentActivitiesAsUser( intent, flags, KeyguardUpdateMonitor.getCurrentUser()); if (appList.size() == 0) { return null; } ResolveInfo resolved = packageManager.resolveActivityAsUser(intent, flags | PackageManager.GET_META_DATA, KeyguardUpdateMonitor.getCurrentUser()); if (wouldLaunchResolverActivity(resolved, appList)) { return null; } if (resolved == null || resolved.activityInfo == null) { return null; } return getWidgetInfoFromMetaData(resolved.activityInfo.packageName, resolved.activityInfo.metaData); } public static boolean wouldLaunchResolverActivity(Context ctx, Intent intent, int currentUserId) { return getTargetActivityInfo(ctx, intent, currentUserId, false /* onlyDirectBootAware */) == null; } /** * @param onlyDirectBootAware a boolean indicating whether the matched activity packages must * be direct boot aware when in direct boot mode if false, all * packages are considered a match even if they are not aware. * @return the target activity info of the intent it resolves to a specific package or * {@code null} if it resolved to the resolver activity */ public static ActivityInfo getTargetActivityInfo(Context ctx, Intent intent, int currentUserId, boolean onlyDirectBootAware) { PackageManager packageManager = ctx.getPackageManager(); int flags = PackageManager.MATCH_DEFAULT_ONLY; if (!onlyDirectBootAware) { flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; } final List appList = packageManager.queryIntentActivitiesAsUser( intent, flags, currentUserId); if (appList.size() == 0) { return null; } ResolveInfo resolved = packageManager.resolveActivityAsUser(intent, flags | PackageManager.GET_META_DATA, currentUserId); if (resolved == null || wouldLaunchResolverActivity(resolved, appList)) { return null; } else { return resolved.activityInfo; } } private static boolean wouldLaunchResolverActivity( ResolveInfo resolved, List appList) { // If the list contains the above resolved activity, then it can't be // ResolverActivity itself. for (int i = 0; i < appList.size(); i++) { ResolveInfo tmp = appList.get(i); if (tmp.activityInfo.name.equals(resolved.activityInfo.name) && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) { return false; } } return true; } private static class WidgetInfo { String contextPackage; int layoutId; } }