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

Commit e230a7d8 authored by Cliff Wu's avatar Cliff Wu
Browse files

Update the strings on app unavailable alert dialog

- Update strings on Settings unavailable alert dialog to match
  UX guidelines.
- Update strings on other apps unavailable alert dialog to
  match UX guidelines.
- Add the test cases.

Bug: 227283466
Test: Manual, atest FrameworksServicesTests:VirtualDeviceManagerServiceTest
Change-Id: I9a527db49e3f6e6d3c147a18a3e4c8e403cda6bd
parent 7038aedd
Loading
Loading
Loading
Loading
+19 −7
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ public class BlockedAppStreamingActivity extends AlertActivity {
    private static final String EXTRA_BLOCKED_ACTIVITY_INFO =
            PACKAGE_NAME + ".extra.BLOCKED_ACTIVITY_INFO";
    private static final String EXTRA_STREAMED_DEVICE = PACKAGE_NAME + ".extra.STREAMED_DEVICE";
    private static final String BLOCKED_COMPONENT_SETTINGS = "com.android.settings";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
@@ -56,13 +57,24 @@ public class BlockedAppStreamingActivity extends AlertActivity {

        CharSequence streamedDeviceName = intent.getCharSequenceExtra(EXTRA_STREAMED_DEVICE);
        if (!TextUtils.isEmpty(streamedDeviceName)) {
            if (TextUtils.equals(activityInfo.packageName,
                        getPackageManager().getPermissionControllerPackageName())) {
                mAlertParams.mTitle =
                    TextUtils.equals(activityInfo.packageName,
                        getPackageManager().getPermissionControllerPackageName())
                            ? getString(R.string.app_streaming_blocked_title_for_permission_dialog)
                            : getString(R.string.app_streaming_blocked_title, appLabel);
                        getString(R.string.app_streaming_blocked_title_for_permission_dialog);
                mAlertParams.mMessage =
                        getString(R.string.app_streaming_blocked_message_for_permission_dialog,
                                streamedDeviceName);
            } else if (TextUtils.equals(activityInfo.packageName, BLOCKED_COMPONENT_SETTINGS)) {
                mAlertParams.mTitle =
                        getString(R.string.app_streaming_blocked_title_for_settings_dialog);
                mAlertParams.mMessage =
                        getString(R.string.app_streaming_blocked_message, streamedDeviceName);
            } else {
                mAlertParams.mTitle =
                        getString(R.string.app_streaming_blocked_title, appLabel);
                mAlertParams.mMessage =
                        getString(R.string.app_streaming_blocked_message, streamedDeviceName);
            }
        } else {
            mAlertParams.mTitle = getString(R.string.app_blocked_title);
            mAlertParams.mMessage = getString(R.string.app_blocked_message, appLabel);
+27 −3
Original line number Diff line number Diff line
@@ -5459,12 +5459,36 @@
    <string name="app_streaming_blocked_title"><xliff:g id="activity" example="Permission dialog">%1$s</xliff:g> unavailable</string>
    <!-- Title of the dialog shown when the permissioncontroller is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_title_for_permission_dialog">Permission needed</string>
    <!-- Title of the dialog shown when the camera permission is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_title_for_camera_dialog">Camera unavailable</string>
    <!-- Title of the dialog shown when the fingerprint permission is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_title_for_fingerprint_dialog">Continue on phone</string>
    <!-- Title of the dialog shown when the microphone permission is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_title_for_microphone_dialog">Microphone unavailable</string>
    <!-- Title of the dialog shown when the settings is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_title_for_settings_dialog" product="tv">Android TV settings unavailable</string>
    <!-- Title of the dialog shown when the settings is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet">Tablet settings unavailable</string>
    <!-- Title of the dialog shown when the settings is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_title_for_settings_dialog" product="default">Phone settings unavailable</string>
    <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_message" product="tv">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your Android TV device instead.</string>
    <string name="app_streaming_blocked_message" product="tv">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g>. Try on your Android TV device instead.</string>
    <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_message" product="tablet">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your tablet instead.</string>
    <string name="app_streaming_blocked_message" product="tablet">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g>. Try on your tablet instead.</string>
    <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_message" product="default">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your phone instead.</string>
    <string name="app_streaming_blocked_message" product="default">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g>. Try on your phone instead.</string>
    <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_message_for_permission_dialog" product="tv">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your Android TV device instead.</string>
    <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_message_for_permission_dialog" product="tablet">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your tablet instead.</string>
    <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_message_for_permission_dialog" product="default">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your phone instead.</string>
    <!-- Message shown when the fingerprint permission is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv">This app is requesting additional security. Try on your Android TV device instead.</string>
    <!-- Message shown when the fingerprint permission is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet">This app is requesting additional security. Try on your tablet instead.</string>
    <!-- Message shown when the fingerprint permission is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
    <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default">This app is requesting additional security. Try on your phone instead.</string>

    <!-- Message displayed in dialog when app is too old to run on this verison of android. [CHAR LIMIT=NONE] -->
    <string name="deprecated_target_sdk_message">This app was built for an older version of Android and may not work properly. Try checking for updates, or contact the developer.</string>
+6 −0
Original line number Diff line number Diff line
@@ -3284,7 +3284,13 @@

  <java-symbol type="string" name="app_streaming_blocked_title" />
  <java-symbol type="string" name="app_streaming_blocked_title_for_permission_dialog" />
  <java-symbol type="string" name="app_streaming_blocked_title_for_camera_dialog" />
  <java-symbol type="string" name="app_streaming_blocked_title_for_fingerprint_dialog" />
  <java-symbol type="string" name="app_streaming_blocked_title_for_microphone_dialog" />
  <java-symbol type="string" name="app_streaming_blocked_title_for_settings_dialog" />
  <java-symbol type="string" name="app_streaming_blocked_message" />
  <java-symbol type="string" name="app_streaming_blocked_message_for_permission_dialog" />
  <java-symbol type="string" name="app_streaming_blocked_message_for_fingerprint_dialog" />

  <!-- Used internally for assistant to launch activity transitions -->
  <java-symbol type="id" name="cross_task_transition" />
+5 −0
Original line number Diff line number Diff line
@@ -283,6 +283,11 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
        return mVirtualAudioController;
    }

    @VisibleForTesting
    SparseArray<GenericWindowPolicyController> getWindowPolicyControllersForTesting() {
        return mWindowPolicyControllers;
    }

    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
    @Override // Binder call
    public void onAudioSessionStarting(int displayId,
+162 −3
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.companion.virtual;

import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;

@@ -26,6 +28,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -36,14 +39,19 @@ import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;

import android.Manifest;
import android.app.WindowConfiguration;
import android.app.admin.DevicePolicyManager;
import android.companion.AssociationInfo;
import android.companion.virtual.IVirtualDeviceActivityListener;
import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.audio.IAudioConfigChangedCallback;
import android.companion.virtual.audio.IAudioRoutingCallback;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.graphics.Point;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputManagerInternal;
@@ -65,11 +73,13 @@ import android.os.WorkSource;
import android.platform.test.annotations.Presubmit;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArraySet;
import android.view.DisplayInfo;
import android.view.KeyEvent;

import androidx.test.InstrumentationRegistry;

import com.android.internal.app.BlockedAppStreamingActivity;
import com.android.server.LocalServices;

import org.junit.Before;
@@ -80,11 +90,21 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.Arrays;

@Presubmit
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class VirtualDeviceManagerServiceTest {

    private static final String NONBLOCKED_APP_PACKAGE_NAME = "com.someapp";
    private static final String PERMISSION_CONTROLLER_PACKAGE_NAME =
            "com.android.permissioncontroller";
    private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
    private static final String VENDING_PACKAGE_NAME = "com.android.vending";
    private static final String GOOGLE_DIALER_PACKAGE_NAME = "com.google.android.dialer";
    private static final String GOOGLE_MAPS_PACKAGE_NAME = "com.google.android.apps.maps";
    private static final String DEVICE_NAME = "device name";
    private static final int DISPLAY_ID = 2;
    private static final int PRODUCT_ID = 10;
@@ -94,10 +114,12 @@ public class VirtualDeviceManagerServiceTest {
    private static final int HEIGHT = 1800;
    private static final int WIDTH = 900;
    private static final Binder BINDER = new Binder("binder");
    private static final int FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES = 0x00000;

    private Context mContext;
    private VirtualDeviceImpl mDeviceImpl;
    private InputController mInputController;
    private AssociationInfo mAssociationInfo;
    @Mock
    private InputController.NativeWrapper mNativeWrapperMock;
    @Mock
@@ -119,6 +141,30 @@ public class VirtualDeviceManagerServiceTest {
    private IAudioRoutingCallback mRoutingCallback;
    @Mock
    private IAudioConfigChangedCallback mConfigChangedCallback;
    @Mock
    private ApplicationInfo mApplicationInfoMock;

    private ArraySet<ComponentName> getBlockedActivities() {
        ArraySet<ComponentName> blockedActivities = new ArraySet<>();
        blockedActivities.add(new ComponentName(SETTINGS_PACKAGE_NAME, SETTINGS_PACKAGE_NAME));
        blockedActivities.add(new ComponentName(VENDING_PACKAGE_NAME, VENDING_PACKAGE_NAME));
        blockedActivities.add(
                new ComponentName(GOOGLE_DIALER_PACKAGE_NAME, GOOGLE_DIALER_PACKAGE_NAME));
        blockedActivities.add(
                new ComponentName(GOOGLE_MAPS_PACKAGE_NAME, GOOGLE_MAPS_PACKAGE_NAME));
        return blockedActivities;
    }

    private ArrayList<ActivityInfo> getActivityInfoList(
            String packageName, String name, boolean displayOnRemoveDevices) {
        ActivityInfo activityInfo = new ActivityInfo();
        activityInfo.packageName = packageName;
        activityInfo.name = name;
        activityInfo.flags = displayOnRemoveDevices
                ? FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES : FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES;
        activityInfo.applicationInfo = mApplicationInfoMock;
        return new ArrayList<>(Arrays.asList(activityInfo));
    }

    @Before
    public void setUp() {
@@ -151,13 +197,18 @@ public class VirtualDeviceManagerServiceTest {
        when(mContext.getSystemService(Context.POWER_SERVICE)).thenReturn(mPowerManager);

        mInputController = new InputController(new Object(), mNativeWrapperMock);
        AssociationInfo associationInfo = new AssociationInfo(1, 0, null,
        mAssociationInfo = new AssociationInfo(1, 0, null,
                MacAddress.BROADCAST_ADDRESS, "", null, true, false, 0, 0);

        VirtualDeviceParams params = new VirtualDeviceParams
                .Builder()
                .setBlockedActivities(getBlockedActivities())
                .build();
        mDeviceImpl = new VirtualDeviceImpl(mContext,
                associationInfo, new Binder(), /* uid */ 0, mInputController,
                mAssociationInfo, new Binder(), /* uid */ 0, mInputController,
                (int associationId) -> {
                }, mPendingTrampolineCallback, mActivityListener,
                new VirtualDeviceParams.Builder().build());
                params);
    }

    @Test
@@ -590,4 +641,112 @@ public class VirtualDeviceManagerServiceTest {
        mDeviceImpl.setShowPointerIcon(true);
        verify(mInputManagerInternalMock, times(3)).setPointerIconVisible(eq(true), anyInt());
    }

    @Test
    public void openNonBlockedAppOnVirtualDisplay_doesNotStartBlockedAlertActivity() {
        mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
        GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                DISPLAY_ID);
        doNothing().when(mContext).startActivityAsUser(any(), any(), any());

        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
                NONBLOCKED_APP_PACKAGE_NAME,
                NONBLOCKED_APP_PACKAGE_NAME, /* displayOnRemoveDevices */ true);
        Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                activityInfos.get(0), mAssociationInfo.getDisplayName());
        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);

        verify(mContext, never()).startActivityAsUser(argThat(intent ->
                intent.filterEquals(blockedAppIntent)), any(), any());
    }

    @Test
    public void openPermissionControllerOnVirtualDisplay_startBlockedAlertActivity() {
        mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
        GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                DISPLAY_ID);
        doNothing().when(mContext).startActivityAsUser(any(), any(), any());

        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
                PERMISSION_CONTROLLER_PACKAGE_NAME,
                PERMISSION_CONTROLLER_PACKAGE_NAME, /* displayOnRemoveDevices */  false);
        Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                activityInfos.get(0), mAssociationInfo.getDisplayName());
        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);

        verify(mContext).startActivityAsUser(argThat(intent ->
                intent.filterEquals(blockedAppIntent)), any(), any());
    }

    @Test
    public void openSettingsOnVirtualDisplay_startBlockedAlertActivity() {
        mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
        GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                DISPLAY_ID);
        doNothing().when(mContext).startActivityAsUser(any(), any(), any());

        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
                SETTINGS_PACKAGE_NAME,
                SETTINGS_PACKAGE_NAME, /* displayOnRemoveDevices */  true);
        Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                activityInfos.get(0), mAssociationInfo.getDisplayName());
        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);

        verify(mContext).startActivityAsUser(argThat(intent ->
                intent.filterEquals(blockedAppIntent)), any(), any());
    }

    @Test
    public void openVendingOnVirtualDisplay_startBlockedAlertActivity() {
        mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
        GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                DISPLAY_ID);
        doNothing().when(mContext).startActivityAsUser(any(), any(), any());

        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
                VENDING_PACKAGE_NAME,
                VENDING_PACKAGE_NAME, /* displayOnRemoveDevices */  true);
        Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                activityInfos.get(0), mAssociationInfo.getDisplayName());
        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);

        verify(mContext).startActivityAsUser(argThat(intent ->
                intent.filterEquals(blockedAppIntent)), any(), any());
    }

    @Test
    public void openGoogleDialerOnVirtualDisplay_startBlockedAlertActivity() {
        mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
        GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                DISPLAY_ID);
        doNothing().when(mContext).startActivityAsUser(any(), any(), any());

        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
                GOOGLE_DIALER_PACKAGE_NAME,
                GOOGLE_DIALER_PACKAGE_NAME, /* displayOnRemoveDevices */  true);
        Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                activityInfos.get(0), mAssociationInfo.getDisplayName());
        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);

        verify(mContext).startActivityAsUser(argThat(intent ->
                intent.filterEquals(blockedAppIntent)), any(), any());
    }

    @Test
    public void openGoogleMapsOnVirtualDisplay_startBlockedAlertActivity() {
        mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
        GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                DISPLAY_ID);
        doNothing().when(mContext).startActivityAsUser(any(), any(), any());

        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
                GOOGLE_MAPS_PACKAGE_NAME,
                GOOGLE_MAPS_PACKAGE_NAME, /* displayOnRemoveDevices */  true);
        Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                activityInfos.get(0), mAssociationInfo.getDisplayName());
        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);

        verify(mContext).startActivityAsUser(argThat(intent ->
                intent.filterEquals(blockedAppIntent)), any(), any());
    }
}