Home | History | Annotate | Download | only in policy
      1 /*
      2  * Copyright (C) 2014 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.android.systemui.statusbar.policy;
     18 
     19 import android.content.ComponentName;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.pm.ActivityInfo;
     23 import android.content.pm.PackageManager;
     24 import android.content.pm.ResolveInfo;
     25 import android.os.Bundle;
     26 import android.util.Log;
     27 import android.view.LayoutInflater;
     28 import android.view.View;
     29 
     30 import com.android.internal.widget.LockPatternUtils;
     31 import com.android.keyguard.KeyguardUpdateMonitor;
     32 import com.android.systemui.statusbar.phone.KeyguardPreviewContainer;
     33 
     34 import java.util.List;
     35 
     36 /**
     37  * Utility class to inflate previews for phone and camera affordance.
     38  */
     39 public class PreviewInflater {
     40 
     41     private static final String TAG = "PreviewInflater";
     42 
     43     private static final String META_DATA_KEYGUARD_LAYOUT = "com.android.keyguard.layout";
     44 
     45     private Context mContext;
     46     private LockPatternUtils mLockPatternUtils;
     47 
     48     public PreviewInflater(Context context, LockPatternUtils lockPatternUtils) {
     49         mContext = context;
     50         mLockPatternUtils = lockPatternUtils;
     51     }
     52 
     53     public View inflatePreview(Intent intent) {
     54         WidgetInfo info = getWidgetInfo(intent);
     55         return inflatePreview(info);
     56     }
     57 
     58     public View inflatePreviewFromService(ComponentName componentName) {
     59         WidgetInfo info = getWidgetInfoFromService(componentName);
     60         return inflatePreview(info);
     61     }
     62 
     63     private KeyguardPreviewContainer inflatePreview(WidgetInfo info) {
     64         if (info == null) {
     65             return null;
     66         }
     67         View v = inflateWidgetView(info);
     68         if (v == null) {
     69             return null;
     70         }
     71         KeyguardPreviewContainer container = new KeyguardPreviewContainer(mContext, null);
     72         container.addView(v);
     73         return container;
     74     }
     75 
     76     private View inflateWidgetView(WidgetInfo widgetInfo) {
     77         View widgetView = null;
     78         try {
     79             Context appContext = mContext.createPackageContext(
     80                     widgetInfo.contextPackage, Context.CONTEXT_RESTRICTED);
     81             LayoutInflater appInflater = (LayoutInflater)
     82                     appContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     83             appInflater = appInflater.cloneInContext(appContext);
     84             widgetView = appInflater.inflate(widgetInfo.layoutId, null, false);
     85         } catch (PackageManager.NameNotFoundException|RuntimeException e) {
     86             Log.w(TAG, "Error creating widget view", e);
     87         }
     88         return widgetView;
     89     }
     90 
     91     private WidgetInfo getWidgetInfoFromService(ComponentName componentName) {
     92         PackageManager packageManager = mContext.getPackageManager();
     93         // Look for the preview specified in the service meta-data
     94         try {
     95             Bundle metaData = packageManager.getServiceInfo(
     96                     componentName, PackageManager.GET_META_DATA).metaData;
     97             return getWidgetInfoFromMetaData(componentName.getPackageName(), metaData);
     98         } catch (PackageManager.NameNotFoundException e) {
     99             Log.w(TAG, "Failed to load preview; " + componentName.flattenToShortString()
    100                     + " not found", e);
    101         }
    102         return null;
    103     }
    104 
    105     private WidgetInfo getWidgetInfoFromMetaData(String contextPackage,
    106             Bundle metaData) {
    107         if (metaData == null) {
    108             return null;
    109         }
    110         int layoutId = metaData.getInt(META_DATA_KEYGUARD_LAYOUT);
    111         if (layoutId == 0) {
    112             return null;
    113         }
    114         WidgetInfo info = new WidgetInfo();
    115         info.contextPackage = contextPackage;
    116         info.layoutId = layoutId;
    117         return info;
    118     }
    119 
    120     private WidgetInfo getWidgetInfo(Intent intent) {
    121         PackageManager packageManager = mContext.getPackageManager();
    122         int flags = PackageManager.MATCH_DEFAULT_ONLY
    123                 | PackageManager.MATCH_DIRECT_BOOT_AWARE
    124                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
    125         final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
    126                 intent, flags, KeyguardUpdateMonitor.getCurrentUser());
    127         if (appList.size() == 0) {
    128             return null;
    129         }
    130         ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
    131                 flags | PackageManager.GET_META_DATA,
    132                 KeyguardUpdateMonitor.getCurrentUser());
    133         if (wouldLaunchResolverActivity(resolved, appList)) {
    134             return null;
    135         }
    136         if (resolved == null || resolved.activityInfo == null) {
    137             return null;
    138         }
    139         return getWidgetInfoFromMetaData(resolved.activityInfo.packageName,
    140                 resolved.activityInfo.metaData);
    141     }
    142 
    143     public static boolean wouldLaunchResolverActivity(Context ctx, Intent intent,
    144             int currentUserId) {
    145         return getTargetActivityInfo(ctx, intent, currentUserId, false /* onlyDirectBootAware */)
    146                 == null;
    147     }
    148 
    149     /**
    150      * @param onlyDirectBootAware a boolean indicating whether the matched activity packages must
    151      *                            be direct boot aware when in direct boot mode if false, all
    152      *                            packages are considered a match even if they are not aware.
    153      * @return the target activity info of the intent it resolves to a specific package or
    154      *         {@code null} if it resolved to the resolver activity
    155      */
    156     public static ActivityInfo getTargetActivityInfo(Context ctx, Intent intent,
    157             int currentUserId, boolean onlyDirectBootAware) {
    158         PackageManager packageManager = ctx.getPackageManager();
    159         int flags = PackageManager.MATCH_DEFAULT_ONLY;
    160         if (!onlyDirectBootAware) {
    161             flags |=  PackageManager.MATCH_DIRECT_BOOT_AWARE
    162                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
    163         }
    164         final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
    165                 intent, flags, currentUserId);
    166         if (appList.size() == 0) {
    167             return null;
    168         }
    169         ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
    170                 flags | PackageManager.GET_META_DATA, currentUserId);
    171         if (resolved == null || wouldLaunchResolverActivity(resolved, appList)) {
    172             return null;
    173         } else {
    174             return resolved.activityInfo;
    175         }
    176     }
    177 
    178     private static boolean wouldLaunchResolverActivity(
    179             ResolveInfo resolved, List<ResolveInfo> appList) {
    180         // If the list contains the above resolved activity, then it can't be
    181         // ResolverActivity itself.
    182         for (int i = 0; i < appList.size(); i++) {
    183             ResolveInfo tmp = appList.get(i);
    184             if (tmp.activityInfo.name.equals(resolved.activityInfo.name)
    185                     && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) {
    186                 return false;
    187             }
    188         }
    189         return true;
    190     }
    191 
    192     private static class WidgetInfo {
    193         String contextPackage;
    194         int layoutId;
    195     }
    196 }
    197