blob: b4365b845e909e6b16e69aab03020be3d64ade48 [file] [log] [blame]
/*
* Copyright (C) 2022 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.intentresolver;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.os.UserHandle;
import android.os.UserManager;
/**
* Helper class to precompute the (immutable) designations of various user handles in the system
* that may contribute to the current Sharesheet session.
*/
public final class AnnotatedUserHandles {
/** The user id of the app that started the share activity. */
public final int userIdOfCallingApp;
/**
* The {@link UserHandle} that launched Sharesheet.
* TODO: I believe this would always be the handle corresponding to {@code userIdOfCallingApp}
* except possibly if the caller used {@link Activity#startActivityAsUser()} to launch
* Sharesheet as a different user than they themselves were running as. Verify and document.
*/
public final UserHandle userHandleSharesheetLaunchedAs;
/**
* The {@link UserHandle} that owns the "personal tab" in a tabbed share UI (or the *only* 'tab'
* in a non-tabbed UI).
*
* This is never a work or clone user, but may either be the root user (0) or a "secondary"
* multi-user profile (i.e., one that's not root, work, nor clone). This is a "secondary"
* profile only when that user is the active "foreground" user.
*
* In the current implementation, we can assert that this is the root user (0) any time we
* display a tabbed UI (i.e., any time `workProfileUserHandle` is non-null), or any time that we
* have a clone profile. This note is only provided for informational purposes; clients should
* avoid making any reliances on that assumption.
*/
public final UserHandle personalProfileUserHandle;
/**
* The {@link UserHandle} that owns the "work tab" in a tabbed share UI. This is (an arbitrary)
* one of the "managed" profiles associated with {@link personalProfileUserHandle}.
*/
@Nullable
public final UserHandle workProfileUserHandle;
/**
* The {@link UserHandle} of the clone profile belonging to {@link personalProfileUserHandle}.
*/
@Nullable
public final UserHandle cloneProfileUserHandle;
/**
* The "tab owner" user handle (i.e., either {@link personalProfileUserHandle} or
* {@link workProfileUserHandle}) that either matches or owns the profile of the
* {@link userHandleSharesheetLaunchedAs}.
*
* In the current implementation, we can assert that this is the same as
* `userHandleSharesheetLaunchedAs` except when the latter is the clone profile; then this is
* the "personal" profile owning that clone profile (which we currently know must belong to
* user 0, but clients should avoid making any reliances on that assumption).
*/
public final UserHandle tabOwnerUserHandleForLaunch;
public AnnotatedUserHandles(Activity forShareActivity) {
userIdOfCallingApp = forShareActivity.getLaunchedFromUid();
if ((userIdOfCallingApp < 0) || UserHandle.isIsolated(userIdOfCallingApp)) {
throw new SecurityException("Can't start a resolver from uid " + userIdOfCallingApp);
}
// TODO: integrate logic for `ResolverActivity.EXTRA_CALLING_USER`.
userHandleSharesheetLaunchedAs = UserHandle.of(UserHandle.myUserId());
personalProfileUserHandle = UserHandle.of(ActivityManager.getCurrentUser());
UserManager userManager = forShareActivity.getSystemService(UserManager.class);
workProfileUserHandle = getWorkProfileForUser(userManager, personalProfileUserHandle);
cloneProfileUserHandle = getCloneProfileForUser(userManager, personalProfileUserHandle);
tabOwnerUserHandleForLaunch = (userHandleSharesheetLaunchedAs == workProfileUserHandle)
? workProfileUserHandle : personalProfileUserHandle;
}
@Nullable
private static UserHandle getWorkProfileForUser(
UserManager userManager, UserHandle profileOwnerUserHandle) {
return userManager.getProfiles(profileOwnerUserHandle.getIdentifier()).stream()
.filter(info -> info.isManagedProfile()).findFirst()
.map(info -> info.getUserHandle()).orElse(null);
}
@Nullable
private static UserHandle getCloneProfileForUser(
UserManager userManager, UserHandle profileOwnerUserHandle) {
return null; // Not yet supported in framework.
}
}