IntentForwarderActivity.java revision ce673ffd228234bdcb986bc44ecd40a201283571
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
17package com.android.internal.app;
18
19import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
20
21import android.app.Activity;
22import android.app.ActivityManagerNative;
23import android.app.AppGlobals;
24import android.os.Bundle;
25import android.content.Context;
26import android.content.Intent;
27import android.content.pm.IPackageManager;
28import android.content.pm.UserInfo;
29import android.os.Process;
30import android.os.RemoteException;
31import android.os.UserHandle;
32import android.os.UserManager;
33import android.util.Slog;
34import android.widget.Toast;
35import java.util.List;
36import java.util.Set;
37
38/*
39 * This is used in conjunction with the {@link setCrossProfileIntentFilter} method of
40 * {@link DevicePolicyManager} to enable intents to be passed in and out of a managed profile.
41 */
42
43public class IntentForwarderActivity extends Activity  {
44
45    public static String TAG = "IntentForwarderActivity";
46
47    public static String FORWARD_INTENT_TO_USER_OWNER
48            = "com.android.internal.app.ForwardIntentToUserOwner";
49
50    public static String FORWARD_INTENT_TO_MANAGED_PROFILE
51            = "com.android.internal.app.ForwardIntentToManagedProfile";
52
53    @Override
54    protected void onCreate(Bundle savedInstanceState) {
55        super.onCreate(savedInstanceState);
56        Intent intentReceived = getIntent();
57
58        String className = intentReceived.getComponent().getClassName();
59        final UserHandle userDest;
60        final int userMessageId;
61
62        if (className.equals(FORWARD_INTENT_TO_USER_OWNER)) {
63            userMessageId = com.android.internal.R.string.forward_intent_to_owner;
64            userDest = UserHandle.OWNER;
65        } else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
66            userMessageId = com.android.internal.R.string.forward_intent_to_work;
67            userDest = getManagedProfile();
68        } else {
69            Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly");
70            userMessageId = -1;
71            userDest = null;
72        }
73        if (userDest == null) { // This covers the case where there is no managed profile.
74            finish();
75            return;
76        }
77        Intent newIntent = new Intent(intentReceived);
78        newIntent.setComponent(null);
79        newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
80                |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
81        int callingUserId = getUserId();
82        IPackageManager ipm = AppGlobals.getPackageManager();
83        String resolvedType = newIntent.resolveTypeIfNeeded(getContentResolver());
84        boolean canForward = false;
85        try {
86            Intent selector = newIntent.getSelector();
87            if (selector == null) {
88                selector = newIntent;
89            }
90            canForward = ipm.canForwardTo(selector, resolvedType, callingUserId,
91                    userDest.getIdentifier());
92        } catch (RemoteException e) {
93            Slog.e(TAG, "PackageManagerService is dead?");
94        }
95        if (canForward) {
96            newIntent.setContentUserHint(callingUserId);
97
98            final android.content.pm.ResolveInfo ri = getPackageManager().resolveActivityAsUser(
99                        newIntent, MATCH_DEFAULT_ONLY, userDest.getIdentifier());
100
101            // Only show a disclosure if this is a normal (non-OS) app
102            final boolean shouldShowDisclosure =
103                    !UserHandle.isSameApp(ri.activityInfo.applicationInfo.uid, Process.SYSTEM_UID);
104
105            startActivityAsUser(newIntent, userDest);
106
107            if (shouldShowDisclosure) {
108                Toast.makeText(this, getString(userMessageId), Toast.LENGTH_LONG).show();
109            }
110        } else {
111            Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user "
112                    + callingUserId + " to user " + userDest.getIdentifier());
113        }
114        finish();
115    }
116
117    /**
118     * Returns the managed profile for this device or null if there is no managed
119     * profile.
120     *
121     * TODO: Remove the assumption that there is only one managed profile
122     * on the device.
123     */
124    private UserHandle getManagedProfile() {
125        UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
126        List<UserInfo> relatedUsers = userManager.getProfiles(UserHandle.USER_OWNER);
127        for (UserInfo userInfo : relatedUsers) {
128            if (userInfo.isManagedProfile()) return new UserHandle(userInfo.id);
129        }
130        Slog.wtf(TAG, FORWARD_INTENT_TO_MANAGED_PROFILE
131                + " has been called, but there is no managed profile");
132        return null;
133    }
134}
135