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

Commit 94240c5a authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Update output switcher behavior and UI design"

parents 843290cc e13e09d1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ public class MediaDeviceUpdateWorker extends SliceBackgroundWorker

    @Override
    public void close() {

        mLocalMediaManager = null;
    }

    @Override
+31 −37
Original line number Diff line number Diff line
@@ -20,13 +20,11 @@ import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_SLICE

import android.annotation.ColorInt;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.UserHandle;
import android.util.IconDrawableFactory;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.VisibleForTesting;
@@ -58,37 +56,48 @@ public class MediaOutputSlice implements CustomSliceable {

    private MediaDeviceUpdateWorker mWorker;
    private String mPackageName;
    private IconDrawableFactory mIconDrawableFactory;

    public MediaOutputSlice(Context context) {
        mContext = context;
        mPackageName = getUri().getQueryParameter(MEDIA_PACKAGE_NAME);
        mIconDrawableFactory = IconDrawableFactory.newInstance(mContext);
    }

    @VisibleForTesting
    void init(String packageName, MediaDeviceUpdateWorker worker, IconDrawableFactory factory) {
    void init(String packageName, MediaDeviceUpdateWorker worker) {
        mPackageName = packageName;
        mWorker = worker;
        mIconDrawableFactory = factory;
    }

    @Override
    public Slice getSlice() {
        final PackageManager pm = mContext.getPackageManager();
        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        if (!adapter.isEnabled()) {
            Log.d(TAG, "getSlice() Bluetooth is off");
            return null;
        }

        final List<MediaDevice> devices = getMediaDevices();
        final CharSequence title = Utils.getApplicationLabel(mContext, mPackageName);
        final CharSequence summary =
                mContext.getString(R.string.media_output_panel_summary_of_playing_device,
                        getConnectedDeviceName());
        @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);

        final Drawable drawable =
                Utils.getBadgedIcon(mIconDrawableFactory, pm, mPackageName, UserHandle.myUserId());
        final IconCompat icon = Utils.createIconWithDrawable(drawable);
        final MediaDevice connectedDevice = getWorker().getCurrentConnectedMediaDevice();
        final ListBuilder listBuilder = buildActiveDeviceHeader(color, connectedDevice);

        @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
        final SliceAction primarySliceAction = SliceAction.createDeeplink(getPrimaryAction(), icon,
        for (MediaDevice device : devices) {
            if (!TextUtils.equals(connectedDevice.getId(), device.getId())) {
                listBuilder.addRow(getMediaDeviceRow(device));
            }
        }

        return listBuilder.build();
    }

    private ListBuilder buildActiveDeviceHeader(@ColorInt int color, MediaDevice device) {
        final String title = device.getName();
        final IconCompat icon = IconCompat.createWithResource(mContext, device.getIcon());

        final PendingIntent broadcastAction =
                getBroadcastIntent(mContext, device.getId(), device.hashCode());
        final SliceAction primarySliceAction = SliceAction.createDeeplink(broadcastAction, icon,
                ListBuilder.ICON_IMAGE, title);

        final ListBuilder listBuilder = new ListBuilder(mContext, MEDIA_OUTPUT_SLICE_URI,
@@ -97,14 +106,10 @@ public class MediaOutputSlice implements CustomSliceable {
                .addRow(new ListBuilder.RowBuilder()
                        .setTitleItem(icon, ListBuilder.ICON_IMAGE)
                        .setTitle(title)
                        .setSubtitle(summary)
                        .setSubtitle(device.getSummary())
                        .setPrimaryAction(primarySliceAction));

        for (MediaDevice device : devices) {
            listBuilder.addRow(getMediaDeviceRow(device));
        }

        return listBuilder.build();
        return listBuilder;
    }

    private MediaDeviceUpdateWorker getWorker() {
@@ -120,18 +125,6 @@ public class MediaOutputSlice implements CustomSliceable {
        return devices;
    }

    private String getConnectedDeviceName() {
        final MediaDevice device = getWorker().getCurrentConnectedMediaDevice();
        return device != null ? device.getName() : "";
    }

    private PendingIntent getPrimaryAction() {
        final PackageManager pm = mContext.getPackageManager();
        final Intent launchIntent = pm.getLaunchIntentForPackage(mPackageName);
        final Intent intent = launchIntent;
        return PendingIntent.getActivity(mContext, 0  /* requestCode */, intent, 0  /* flags */);
    }

    private ListBuilder.RowBuilder getMediaDeviceRow(MediaDevice device) {
        final String title = device.getName();
        final PendingIntent broadcastAction =
@@ -141,7 +134,8 @@ public class MediaOutputSlice implements CustomSliceable {
                .setTitleItem(deviceIcon, ListBuilder.ICON_IMAGE)
                .setPrimaryAction(SliceAction.create(broadcastAction, deviceIcon,
                        ListBuilder.ICON_IMAGE, title))
                .setTitle(title);
                .setTitle(title)
                .setSubtitle(device.getSummary());

        return rowBuilder;
    }
+2 −11
Original line number Diff line number Diff line
@@ -16,13 +16,11 @@

package com.android.settings.panel;

import static com.android.settingslib.media.MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT;
import static com.android.settingslib.media.MediaOutputSliceConstants.EXTRA_PACKAGE_NAME;

import android.app.settings.SettingsEnums;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
@@ -75,15 +73,8 @@ public class SettingsPanelActivity extends FragmentActivity {
            return;
        }

        final String mediaPackageName =
                callingIntent.getStringExtra(EXTRA_PACKAGE_NAME);

        if (TextUtils.equals(ACTION_MEDIA_OUTPUT, callingIntent.getAction())
                && TextUtils.isEmpty(mediaPackageName)) {
            Log.e(TAG, "Missing EXTRA_PACKAGE_NAME, closing Panel Activity");
            finish();
            return;
        }
        // We will use it once media output switch panel support remote device.
        final String mediaPackageName = callingIntent.getStringExtra(EXTRA_PACKAGE_NAME);

        setContentView(R.layout.settings_panel);

+21 −32
Original line number Diff line number Diff line
@@ -21,21 +21,15 @@ import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_SLICE

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

import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.util.IconDrawableFactory;

import androidx.slice.Slice;
import androidx.slice.SliceMetadata;
@@ -43,6 +37,7 @@ import androidx.slice.SliceProvider;
import androidx.slice.core.SliceAction;
import androidx.slice.widget.SliceLiveData;

import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;

@@ -53,70 +48,64 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;

import java.util.ArrayList;
import java.util.List;

@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothAdapter.class})
public class MediaOutputSliceTest {

    private static final String TEST_PACKAGE_NAME = "com.fake.android.music";
    private static final String TEST_LABEL = "Test app";
    private static final String TEST_DEVICE_1_ID = "test_device_1_id";
    private static final String TEST_DEVICE_1_NAME = "test_device_1_name";
    private static final int TEST_DEVICE_1_ICON =
            com.android.internal.R.drawable.ic_bt_headphones_a2dp;

    @Mock
    private PackageManager mPackageManager;
    @Mock
    private ApplicationInfo mApplicationInfo;
    @Mock
    private ApplicationInfo mApplicationInfo2;
    @Mock
    private LocalMediaManager mLocalMediaManager;
    @Mock
    private IconDrawableFactory mIconDrawableFactory;
    @Mock
    private Drawable mTestDrawable;

    private final List<MediaDevice> mDevices = new ArrayList<>();

    private Context mContext;
    private MediaOutputSlice mMediaOutputSlice;
    private MediaDeviceUpdateWorker mMediaDeviceUpdateWorker;
    private ShadowBluetoothAdapter mShadowBluetoothAdapter;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        mContext = spy(RuntimeEnvironment.application);

        when(mContext.getPackageManager()).thenReturn(mPackageManager);
        when(mPackageManager.getApplicationInfo(eq(TEST_PACKAGE_NAME), anyInt()))
                .thenReturn(mApplicationInfo);
        when(mPackageManager.getApplicationInfoAsUser(eq(TEST_PACKAGE_NAME), anyInt(), anyInt()))
                .thenReturn(mApplicationInfo2);
        when(mApplicationInfo.loadLabel(mPackageManager)).thenReturn(TEST_LABEL);
        when(mIconDrawableFactory.getBadgedIcon(mApplicationInfo2, UserHandle.myUserId()))
                .thenReturn(mTestDrawable);
        when(mTestDrawable.getIntrinsicWidth()).thenReturn(100);
        when(mTestDrawable.getIntrinsicHeight()).thenReturn(100);

        // Set-up specs for SliceMetadata.
        SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
        // Setup BluetoothAdapter
        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
        mShadowBluetoothAdapter.setEnabled(true);

        mMediaOutputSlice = new MediaOutputSlice(mContext);
        mMediaDeviceUpdateWorker = new MediaDeviceUpdateWorker(mContext, MEDIA_OUTPUT_SLICE_URI);
        mMediaDeviceUpdateWorker.setPackageName(TEST_PACKAGE_NAME);
        mMediaDeviceUpdateWorker.onDeviceListUpdate(mDevices);
        mMediaDeviceUpdateWorker.mLocalMediaManager = mLocalMediaManager;
        mMediaOutputSlice.init(TEST_PACKAGE_NAME, mMediaDeviceUpdateWorker, mIconDrawableFactory);
        mMediaOutputSlice.init(TEST_PACKAGE_NAME, mMediaDeviceUpdateWorker);
    }

    @Test
    public void getSlice_shouldHaveAppTitle() {
    public void getSlice_shouldHaveActiveDeviceName() {
        mDevices.clear();
        final MediaDevice device = mock(MediaDevice.class);
        when(device.getName()).thenReturn(TEST_DEVICE_1_NAME);
        when(device.getIcon()).thenReturn(TEST_DEVICE_1_ICON);
        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(device);

        final Slice mediaSlice = mMediaOutputSlice.getSlice();
        final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice);

        final SliceAction primaryAction = metadata.getPrimaryAction();
        assertThat(primaryAction.getTitle().toString()).isEqualTo(TEST_LABEL);
        assertThat(primaryAction.getTitle().toString()).isEqualTo(TEST_DEVICE_1_NAME);
    }

    @Test
+4 −3
Original line number Diff line number Diff line
@@ -76,15 +76,16 @@ public class SettingsPanelActivityTest {
    }

    @Test
    public void startMediaOutputSlice_withoutPackageName_bundleShouldNotHaveValue() {
    public void startMediaOutputSlice_withoutPackageName_bundleShouldHaveValue() {
        final Intent intent = new Intent()
                .setAction("com.android.settings.panel.action.MEDIA_OUTPUT");

        final SettingsPanelActivity activity =
                Robolectric.buildActivity(SettingsPanelActivity.class, intent).create().get();

        assertThat(activity.mBundle.containsKey(KEY_MEDIA_PACKAGE_NAME)).isFalse();
        assertThat(activity.mBundle.containsKey(KEY_PANEL_TYPE_ARGUMENT)).isFalse();
        assertThat(activity.mBundle.containsKey(KEY_MEDIA_PACKAGE_NAME)).isTrue();
        assertThat(activity.mBundle.getString(KEY_PANEL_TYPE_ARGUMENT))
                .isEqualTo("com.android.settings.panel.action.MEDIA_OUTPUT");
    }

    @Test