KeyguardActivityLauncher.java revision dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4b
1/*
2 * Copyright (C) 2012 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
17package com.android.internal.policy.impl.keyguard;
18
19import android.app.ActivityManagerNative;
20import android.content.ActivityNotFoundException;
21import android.content.Context;
22import android.content.Intent;
23import android.content.pm.PackageManager;
24import android.content.pm.ResolveInfo;
25import android.os.RemoteException;
26import android.os.UserHandle;
27import android.provider.MediaStore;
28import android.util.Log;
29import android.view.WindowManager;
30
31import com.android.internal.widget.LockPatternUtils;
32
33import java.util.List;
34
35public abstract class KeyguardActivityLauncher {
36    private static final String TAG = KeyguardActivityLauncher.class.getSimpleName();
37    private static final boolean DEBUG = KeyguardHostView.DEBUG;
38    private static final String META_DATA_KEYGUARD_LAYOUT = "com.android.keyguard.layout";
39    private static final Intent SECURE_CAMERA_INTENT =
40            new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
41                    .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
42    private static final Intent INSECURE_CAMERA_INTENT =
43            new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
44
45    abstract Context getContext();
46
47    abstract KeyguardSecurityCallback getCallback();
48
49    abstract LockPatternUtils getLockPatternUtils();
50
51    public static class CameraWidgetInfo {
52        public String contextPackage;
53        public int layoutId;
54    }
55
56    public CameraWidgetInfo getCameraWidgetInfo() {
57        CameraWidgetInfo info = new CameraWidgetInfo();
58        Intent intent = getCameraIntent();
59        PackageManager packageManager = getContext().getPackageManager();
60        final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
61                intent, PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser());
62        if (appList.size() == 0) {
63            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): Nothing found");
64            return null;
65        }
66        ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
67                PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
68                getLockPatternUtils().getCurrentUser());
69        if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): resolved: " + resolved);
70        if (wouldLaunchResolverActivity(resolved, appList)) {
71            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): Would launch resolver");
72            return info;
73        }
74        if (resolved == null || resolved.activityInfo == null) {
75            return null;
76        }
77        if (resolved.activityInfo.metaData == null || resolved.activityInfo.metaData.isEmpty()) {
78            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): no metadata found");
79            return info;
80        }
81        int layoutId = resolved.activityInfo.metaData.getInt(META_DATA_KEYGUARD_LAYOUT);
82        if (layoutId == 0) {
83            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): no layout specified");
84            return info;
85        }
86        info.contextPackage = resolved.activityInfo.packageName;
87        info.layoutId = layoutId;
88        return info;
89    }
90
91    public void launchCamera() {
92        LockPatternUtils lockPatternUtils = getLockPatternUtils();
93        if (lockPatternUtils.isSecure()) {
94            // Launch the secure version of the camera
95            if (wouldLaunchResolverActivity(SECURE_CAMERA_INTENT)) {
96                // TODO: Show disambiguation dialog instead.
97                // For now, we'll treat this like launching any other app from secure keyguard.
98                // When they do, user sees the system's ResolverActivity which lets them choose
99                // which secure camera to use.
100                launchActivity(SECURE_CAMERA_INTENT, false);
101            } else {
102                launchActivity(SECURE_CAMERA_INTENT, true);
103            }
104        } else {
105//            wouldLaunchResolverActivity(new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA));
106            // Launch the normal camera
107            launchActivity(INSECURE_CAMERA_INTENT, false);
108        }
109    }
110
111    /**
112     * Launches the said intent for the current foreground user.
113     * @param intent
114     * @param showsWhileLocked true if the activity can be run on top of keyguard.
115     * See {@link WindowManager#FLAG_SHOW_WHEN_LOCKED}
116     */
117    public void launchActivity(final Intent intent, boolean showsWhileLocked) {
118        final Context context = getContext();
119        LockPatternUtils lockPatternUtils = getLockPatternUtils();
120        intent.addFlags(
121                Intent.FLAG_ACTIVITY_NEW_TASK
122                | Intent.FLAG_ACTIVITY_SINGLE_TOP
123                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
124        boolean isSecure = lockPatternUtils.isSecure();
125        if (!isSecure || showsWhileLocked) {
126            if (!isSecure) try {
127                ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
128            } catch (RemoteException e) {
129                Log.w(TAG, "can't dismiss keyguard on launch");
130            }
131            try {
132                context.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
133            } catch (ActivityNotFoundException e) {
134                Log.w(TAG, "Activity not found for intent + " + intent.getAction());
135            }
136        } else {
137            // Create a runnable to start the activity and ask the user to enter their
138            // credentials.
139            KeyguardSecurityCallback callback = getCallback();
140            callback.setOnDismissRunnable(new Runnable() {
141                @Override
142                public void run() {
143                    context.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
144                }
145            });
146            callback.dismiss(false);
147        }
148    }
149
150    private Intent getCameraIntent() {
151        return getLockPatternUtils().isSecure() ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
152    }
153
154    private boolean wouldLaunchResolverActivity(Intent intent) {
155        PackageManager packageManager = getContext().getPackageManager();
156        ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
157                PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser());
158        List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
159                intent, PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser());
160        return wouldLaunchResolverActivity(resolved, appList);
161    }
162
163    private boolean wouldLaunchResolverActivity(ResolveInfo resolved, List<ResolveInfo> appList) {
164        // If the list contains the above resolved activity, then it can't be
165        // ResolverActivity itself.
166        for (int i = 0; i < appList.size(); i++) {
167            ResolveInfo tmp = appList.get(i);
168            if (tmp.activityInfo.name.equals(resolved.activityInfo.name)
169                    && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) {
170                return false;
171            }
172        }
173        return true;
174    }
175}
176