Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cd4a8a11 authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

Conditionally initialize IMMS#mCurrentUserId with a main user

With an assumption that we would enable concurrent multi-user IME
support only in an environment where user 0 is not the main user, this
CL changes how

  InputMethodManagerService#mCurrentUserId

is initialized when IMMS#mExperimentalConcurrentMultiUserModeEnabled
is set to true. With this CL it will be initialized to be the first
found main user ID instead of the current user ID when IMMS is
initialized.

Note that this behavior change is fully guarded behind

  IMMS#mExperimentalConcurrentMultiUserModeEnabled

hence there must be no observable behavior changes in other
environments.

Bug: 341558132
Flag: android.view.inputmethod.concurrent_input_methods
Test: presubmit
Test: atest FrameworksInputMethodSystemServerTests
Change-Id: Ie2ee161bea771c5928b504bee494813ac8e1fb7b
parent e03efadb
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -1274,7 +1274,15 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
            InputMethodSettingsRepository.initialize(mHandler, mContext);
            AdditionalSubtypeMapRepository.initialize(mHandler, mContext);

            mCurrentUserId = mActivityManagerInternal.getCurrentUserId();
            final int currentUserId = mActivityManagerInternal.getCurrentUserId();

            // For concurrent multi-user mode, we try to initialize mCurrentUserId with main
            // user rather than the current user when possible.
            mCurrentUserId = mExperimentalConcurrentMultiUserModeEnabled
                    ? MultiUserUtils.getFirstMainUserIdOrDefault(
                            mUserManagerInternal, currentUserId)
                    : currentUserId;

            @SuppressWarnings("GuardedBy") final IntFunction<InputMethodBindingController>
                    bindingControllerFactory = userId -> new InputMethodBindingController(userId,
                    InputMethodManagerService.this);
+55 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.server.inputmethod;

import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.UserIdInt;

import com.android.server.pm.UserManagerInternal;

final class MultiUserUtils {
    /**
     * Not intended to be instantiated.
     */
    private MultiUserUtils() {
    }

    /**
     * Return the first user ID (a user has {@link android.content.pm.UserInfo#FLAG_MAIN} if
     * available). Otherwise, return the given default value.
     *
     * @param userManagerInternal {@link UserManagerInternal} to be used to query about users
     * @param defaultValue a user ID that will be returned when there is no main user
     * @return The first main user ID
     */
    @AnyThread
    @UserIdInt
    static int getFirstMainUserIdOrDefault(@NonNull UserManagerInternal userManagerInternal,
            @UserIdInt int defaultValue) {
        final int[] userIds = userManagerInternal.getUserIds();
        if (userIds != null) {
            for (int userId : userIds) {
                final var userInfo = userManagerInternal.getUserInfo(userId);
                if (userInfo.isMain()) {
                    return userId;
                }
            }
        }
        return defaultValue;
    }
}
+11 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import static org.mockito.Mockito.when;
import android.app.ActivityManagerInternal;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.hardware.input.IInputManager;
import android.hardware.input.InputManagerGlobal;
@@ -207,6 +208,16 @@ public class InputMethodManagerServiceTestBase {
        when(mMockUserManagerInternal.getProfileIds(anyInt(), anyBoolean()))
                .thenReturn(new int[] {0});
        when(mMockUserManagerInternal.getUserIds()).thenReturn(new int[] {0});
        when(mMockUserManagerInternal.getUserInfo(anyInt())).thenAnswer(invocation -> {
            final int userId = invocation.getArgument(0);
            if (userId == 0) {
                new UserInfo(userId, "main",
                        UserInfo.FLAG_PRIMARY | UserInfo.FLAG_MAIN | UserInfo.FLAG_SYSTEM);
            }
            // TODO(b/315348827): Update mock for multi-user scenarios.
            throw new UnsupportedOperationException(
                    "Please mock #getUserInfo for userId=" + userId);
        });
        when(mMockActivityManagerInternal.isSystemReady()).thenReturn(true);
        when(mMockActivityManagerInternal.getCurrentUserId()).thenReturn(mCallingUserId);
        when(mMockPackageManagerInternal.getPackageUid(anyString(), anyLong(), anyInt()))