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.PackageManager;
23 import android.content.pm.ResolveInfo;
24 import android.os.Bundle;
25 import android.util.Log;
26 import android.view.LayoutInflater;
27 import android.view.View;
28 
29 import com.android.internal.widget.LockPatternUtils;
30 import com.android.keyguard.KeyguardUpdateMonitor;
31 import com.android.systemui.ActivityIntentHelper;
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     private final ActivityIntentHelper mActivityIntentHelper;
45 
46     private Context mContext;
47     private LockPatternUtils mLockPatternUtils;
48 
PreviewInflater(Context context, LockPatternUtils lockPatternUtils, ActivityIntentHelper activityIntentHelper)49     public PreviewInflater(Context context, LockPatternUtils lockPatternUtils,
50             ActivityIntentHelper activityIntentHelper) {
51         mContext = context;
52         mLockPatternUtils = lockPatternUtils;
53         mActivityIntentHelper = activityIntentHelper;
54     }
55 
inflatePreview(Intent intent)56     public View inflatePreview(Intent intent) {
57         WidgetInfo info = getWidgetInfo(intent);
58         return inflatePreview(info);
59     }
60 
inflatePreviewFromService(ComponentName componentName)61     public View inflatePreviewFromService(ComponentName componentName) {
62         WidgetInfo info = getWidgetInfoFromService(componentName);
63         return inflatePreview(info);
64     }
65 
inflatePreview(WidgetInfo info)66     private KeyguardPreviewContainer inflatePreview(WidgetInfo info) {
67         if (info == null) {
68             return null;
69         }
70         View v = inflateWidgetView(info);
71         if (v == null) {
72             return null;
73         }
74         KeyguardPreviewContainer container = new KeyguardPreviewContainer(mContext, null);
75         container.addView(v);
76         return container;
77     }
78 
inflateWidgetView(WidgetInfo widgetInfo)79     private View inflateWidgetView(WidgetInfo widgetInfo) {
80         View widgetView = null;
81         try {
82             Context appContext = mContext.createPackageContext(
83                     widgetInfo.contextPackage, Context.CONTEXT_RESTRICTED);
84             LayoutInflater appInflater = (LayoutInflater)
85                     appContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
86             appInflater = appInflater.cloneInContext(appContext);
87             widgetView = appInflater.inflate(widgetInfo.layoutId, null, false);
88         } catch (PackageManager.NameNotFoundException|RuntimeException e) {
89             Log.w(TAG, "Error creating widget view", e);
90         }
91         return widgetView;
92     }
93 
getWidgetInfoFromService(ComponentName componentName)94     private WidgetInfo getWidgetInfoFromService(ComponentName componentName) {
95         PackageManager packageManager = mContext.getPackageManager();
96         // Look for the preview specified in the service meta-data
97         try {
98             Bundle metaData = packageManager.getServiceInfo(
99                     componentName, PackageManager.GET_META_DATA).metaData;
100             return getWidgetInfoFromMetaData(componentName.getPackageName(), metaData);
101         } catch (PackageManager.NameNotFoundException e) {
102             Log.w(TAG, "Failed to load preview; " + componentName.flattenToShortString()
103                     + " not found", e);
104         }
105         return null;
106     }
107 
getWidgetInfoFromMetaData(String contextPackage, Bundle metaData)108     private WidgetInfo getWidgetInfoFromMetaData(String contextPackage,
109             Bundle metaData) {
110         if (metaData == null) {
111             return null;
112         }
113         int layoutId = metaData.getInt(META_DATA_KEYGUARD_LAYOUT);
114         if (layoutId == 0) {
115             return null;
116         }
117         WidgetInfo info = new WidgetInfo();
118         info.contextPackage = contextPackage;
119         info.layoutId = layoutId;
120         return info;
121     }
122 
getWidgetInfo(Intent intent)123     private WidgetInfo getWidgetInfo(Intent intent) {
124         PackageManager packageManager = mContext.getPackageManager();
125         int flags = PackageManager.MATCH_DEFAULT_ONLY
126                 | PackageManager.MATCH_DIRECT_BOOT_AWARE
127                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
128         final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
129                 intent, flags, KeyguardUpdateMonitor.getCurrentUser());
130         if (appList.size() == 0) {
131             return null;
132         }
133         ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
134                 flags | PackageManager.GET_META_DATA,
135                 KeyguardUpdateMonitor.getCurrentUser());
136         if (mActivityIntentHelper.wouldLaunchResolverActivity(resolved, appList)) {
137             return null;
138         }
139         if (resolved == null || resolved.activityInfo == null) {
140             return null;
141         }
142         return getWidgetInfoFromMetaData(resolved.activityInfo.packageName,
143                 resolved.activityInfo.metaData);
144     }
145 
146     private static class WidgetInfo {
147         String contextPackage;
148         int layoutId;
149     }
150 }
151