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

Commit 5daa4727 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Update output chooser for calls

- Hide media routes while in call
- Change the title while in call
- Add a title while not in call, too

Bug: 63096355
Test: manual
Change-Id: Ib7bcd314efb010fe903327dd4d9bdbfe521c1f73
parent 4f9750c4
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<!-- extends FrameLayout -->
<!-- extends LinearLayout -->
<com.android.systemui.volume.OutputChooserLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:sysui="http://schemas.android.com/apk/res-auto"
@@ -23,8 +23,17 @@
    android:minHeight="320dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="20dp" >

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textDirection="locale"
        android:textAppearance="@style/TextAppearance.QS.DetailHeader"
        android:layout_marginBottom="20dp" />

    <com.android.systemui.qs.AutoSizingList
        android:id="@android:id/list"
        android:layout_width="match_parent"
@@ -42,9 +51,10 @@
        android:orientation="vertical">

        <TextView
            android:id="@android:id/title"
            android:id="@+id/empty_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textDirection="locale"
            android:layout_marginTop="20dp"
            android:textAppearance="@style/TextAppearance.QS.DetailEmpty"/>
    </LinearLayout>
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
        android:layout_height="@dimen/qs_detail_item_icon_size"
        android:layout_marginStart="@dimen/qs_detail_item_icon_marginStart"
        android:layout_marginEnd="@dimen/qs_detail_item_icon_marginEnd"
        android:background="?android:selectableItemBackgroundBorderless"
        android:tint="?android:attr/textColorPrimary"/>

    <LinearLayout
+51 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.systemui.volume;

import android.support.v7.media.MediaRouteSelector;
import android.support.v7.media.MediaRouter;

import java.util.List;

/**
 * Wrapper for final class MediaRouter, for testing.
 */
public class MediaRouterWrapper {

    private final MediaRouter mRouter;

    public MediaRouterWrapper(MediaRouter router)
    {
        mRouter = router;
    }

    public void addCallback(MediaRouteSelector selector, MediaRouter.Callback callback, int flags) {
        mRouter.addCallback(selector, callback, flags);
    }

    public void removeCallback(MediaRouter.Callback callback) {
        mRouter.removeCallback(callback);
    }

    public void unselect(int reason) {
        mRouter.unselect(reason);
    }

    public List<MediaRouter.RouteInfo> getRoutes() {
        return mRouter.getRoutes();
    }
}
 No newline at end of file
+55 −37
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 * Copyright (C) 2017 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.
@@ -40,6 +40,7 @@ import android.os.SystemClock;
import android.support.v7.media.MediaControlIntent;
import android.support.v7.media.MediaRouteSelector;
import android.support.v7.media.MediaRouter;
import android.telecom.TelecomManager;
import android.util.Log;
import android.util.Pair;

@@ -54,7 +55,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

@@ -65,15 +65,17 @@ public class OutputChooserDialog extends SystemUIDialog
    private static final int MAX_DEVICES = 10;

    private static final long UPDATE_DELAY_MS = 300L;
    static final int MSG_UPDATE_ITEMS = 1;
    private static final int MSG_UPDATE_ITEMS = 1;

    private final Context mContext;
    private final BluetoothController mController;
    private final WifiManager mWifiManager;
    private final BluetoothController mBluetoothController;
    private WifiManager mWifiManager;
    private OutputChooserLayout mView;
    private final MediaRouter mRouter;
    private final MediaRouterWrapper mRouter;
    private final MediaRouterCallback mRouterCallback;
    private long mLastUpdateTime;
    private boolean mIsInCall;
    protected boolean isAttached;

    private final MediaRouteSelector mRouteSelector;
    private Drawable mDefaultIcon;
@@ -81,12 +83,14 @@ public class OutputChooserDialog extends SystemUIDialog
    private Drawable mSpeakerIcon;
    private Drawable mSpeakerGroupIcon;

    public OutputChooserDialog(Context context) {
    public OutputChooserDialog(Context context, MediaRouterWrapper router) {
        super(context);
        mContext = context;
        mController = Dependency.get(BluetoothController.class);
        mBluetoothController = Dependency.get(BluetoothController.class);
        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        mRouter = MediaRouter.getInstance(context);
        TelecomManager tm = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
        mIsInCall = tm.isInCall();
        mRouter = router;
        mRouterCallback = new MediaRouterCallback();
        mRouteSelector = new MediaRouteSelector.Builder()
                .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
@@ -96,27 +100,38 @@ public class OutputChooserDialog extends SystemUIDialog
        context.registerReceiver(mReceiver, filter);
    }

    protected void setIsInCall(boolean inCall) {
        mIsInCall = inCall;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.output_chooser);
        setCanceledOnTouchOutside(true);
        setOnDismissListener(this::onDismiss);
        setTitle(R.string.output_title);

        mView = findViewById(R.id.output_chooser);
        mView.setCallback(this);

        if (mIsInCall) {
            mView.setTitle(R.string.output_calls_title);
        } else {
            mView.setTitle(R.string.output_title);
        }

        mDefaultIcon = mContext.getDrawable(R.drawable.ic_cast);
        mTvIcon = mContext.getDrawable(R.drawable.ic_tv);
        mSpeakerIcon = mContext.getDrawable(R.drawable.ic_speaker);
        mSpeakerGroupIcon = mContext.getDrawable(R.drawable.ic_speaker_group);

        final boolean wifiOff = !mWifiManager.isWifiEnabled();
        final boolean btOff = !mController.isBluetoothEnabled();
        if (wifiOff || btOff) {
        final boolean btOff = !mBluetoothController.isBluetoothEnabled();
        if (wifiOff && btOff) {
            mView.setEmptyState(getDisabledServicesMessage(wifiOff, btOff));
        }
        // time out after 5 seconds
        mView.postDelayed(() -> updateItems(true), 5000);
    }

    protected void cleanUp() {}
@@ -131,15 +146,19 @@ public class OutputChooserDialog extends SystemUIDialog
    public void onAttachedToWindow() {
        super.onAttachedToWindow();

        if (!mIsInCall) {
            mRouter.addCallback(mRouteSelector, mRouterCallback,
                    MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
        mController.addCallback(mCallback);
        }
        mBluetoothController.addCallback(mCallback);
        isAttached = true;
    }

    @Override
    public void onDetachedFromWindow() {
        isAttached = false;
        mRouter.removeCallback(mRouterCallback);
        mController.removeCallback(mCallback);
        mBluetoothController.removeCallback(mCallback);
        super.onDetachedFromWindow();
    }

@@ -154,9 +173,8 @@ public class OutputChooserDialog extends SystemUIDialog
        if (item == null || item.tag == null) return;
        if (item.deviceType == OutputChooserLayout.Item.DEVICE_TYPE_BT) {
            final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
            if (device != null && device.getMaxConnectionState()
                    == BluetoothProfile.STATE_DISCONNECTED) {
                mController.connect(device);
            if (device.getMaxConnectionState() == BluetoothProfile.STATE_DISCONNECTED) {
                mBluetoothController.connect(device);
            }
        } else if (item.deviceType == OutputChooserLayout.Item.DEVICE_TYPE_MEDIA_ROUTER) {
            final MediaRouter.RouteInfo route = (MediaRouter.RouteInfo) item.tag;
@@ -171,18 +189,16 @@ public class OutputChooserDialog extends SystemUIDialog
        if (item == null || item.tag == null) return;
        if (item.deviceType == OutputChooserLayout.Item.DEVICE_TYPE_BT) {
            final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
            if (device != null) {
                mController.disconnect(device);
            }
            mBluetoothController.disconnect(device);
        } else if (item.deviceType == OutputChooserLayout.Item.DEVICE_TYPE_MEDIA_ROUTER) {
            mRouter.unselect(UNSELECT_REASON_DISCONNECTED);
        }
    }

    private void updateItems() {
    private void updateItems(boolean timeout) {
        if (SystemClock.uptimeMillis() - mLastUpdateTime < UPDATE_DELAY_MS) {
            mHandler.removeMessages(MSG_UPDATE_ITEMS);
            mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_UPDATE_ITEMS),
            mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_UPDATE_ITEMS, timeout),
                    mLastUpdateTime + UPDATE_DELAY_MS);
            return;
        }
@@ -194,14 +210,16 @@ public class OutputChooserDialog extends SystemUIDialog
        addBluetoothDevices(items);

        // Add remote displays
        if (!mIsInCall) {
            addRemoteDisplayRoutes(items);
        }

        Collections.sort(items, ItemComparator.sInstance);
        items.sort(ItemComparator.sInstance);

        if (items.size() == 0) {
        if (items.size() == 0 && timeout) {
            String emptyMessage = mContext.getString(R.string.output_none_found);
            final boolean wifiOff = !mWifiManager.isWifiEnabled();
            final boolean btOff = !mController.isBluetoothEnabled();
            final boolean btOff = !mBluetoothController.isBluetoothEnabled();
            if (wifiOff || btOff) {
                emptyMessage = getDisabledServicesMessage(wifiOff, btOff);
            }
@@ -219,12 +237,12 @@ public class OutputChooserDialog extends SystemUIDialog
    }

    private void addBluetoothDevices(List<OutputChooserLayout.Item> items) {
        final Collection<CachedBluetoothDevice> devices = mController.getDevices();
        final Collection<CachedBluetoothDevice> devices = mBluetoothController.getDevices();
        if (devices != null) {
            int connectedDevices = 0;
            int count = 0;
            for (CachedBluetoothDevice device : devices) {
                if (mController.getBondState(device) == BluetoothDevice.BOND_NONE) continue;
                if (mBluetoothController.getBondState(device) == BluetoothDevice.BOND_NONE) continue;
                final int majorClass = device.getBtClass().getMajorDeviceClass();
                if (majorClass != BluetoothClass.Device.Major.AUDIO_VIDEO
                        && majorClass != BluetoothClass.Device.Major.UNCATEGORIZED) {
@@ -328,22 +346,22 @@ public class OutputChooserDialog extends SystemUIDialog
    private final class MediaRouterCallback extends MediaRouter.Callback {
        @Override
        public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
            updateItems();
            updateItems(false);
        }

        @Override
        public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) {
            updateItems();
            updateItems(false);
        }

        @Override
        public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) {
            updateItems();
            updateItems(false);
        }

        @Override
        public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo route) {
            dismiss();
            updateItems(false);
        }
    }

@@ -361,12 +379,12 @@ public class OutputChooserDialog extends SystemUIDialog
    private final BluetoothController.Callback mCallback = new BluetoothController.Callback() {
        @Override
        public void onBluetoothStateChange(boolean enabled) {
            updateItems();
            updateItems(false);
        }

        @Override
        public void onBluetoothDevicesChanged() {
            updateItems();
            updateItems(false);
        }
    };

@@ -393,7 +411,7 @@ public class OutputChooserDialog extends SystemUIDialog
        public void handleMessage(Message message) {
            switch (message.what) {
                case MSG_UPDATE_ITEMS:
                    updateItems();
                    updateItems((Boolean) message.obj);
                    break;
            }
        }
+13 −15
Original line number Diff line number Diff line
@@ -29,8 +29,8 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.android.systemui.FontSizeUtils;
@@ -40,11 +40,10 @@ import com.android.systemui.qs.AutoSizingList;
/**
 * Limited height list of devices.
 */
public class OutputChooserLayout extends FrameLayout {
public class OutputChooserLayout extends LinearLayout {
    private static final String TAG = "OutputChooserLayout";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private final int mQsDetailIconOverlaySize;
    private final Context mContext;
    private final H mHandler = new H();
    private final Adapter mAdapter = new Adapter();
@@ -55,6 +54,7 @@ public class OutputChooserLayout extends FrameLayout {
    private AutoSizingList mItemList;
    private View mEmpty;
    private TextView mEmptyText;
    private TextView mTitle;

    private Item[] mItems;

@@ -62,8 +62,6 @@ public class OutputChooserLayout extends FrameLayout {
        super(context, attrs);
        mContext = context;
        mTag = TAG;
        mQsDetailIconOverlaySize = (int) getResources().getDimension(
                R.dimen.qs_detail_icon_overlay_size);
    }

    @Override
@@ -74,7 +72,8 @@ public class OutputChooserLayout extends FrameLayout {
        mItemList.setAdapter(mAdapter);
        mEmpty = findViewById(android.R.id.empty);
        mEmpty.setVisibility(GONE);
        mEmptyText = mEmpty.findViewById(android.R.id.title);
        mEmptyText = mEmpty.findViewById(R.id.empty_text);
        mTitle = findViewById(R.id.title);
    }

    @Override
@@ -84,17 +83,21 @@ public class OutputChooserLayout extends FrameLayout {
        int count = mItemList.getChildCount();
        for (int i = 0; i < count; i++) {
            View item = mItemList.getChildAt(i);
            FontSizeUtils.updateFontSize(item, android.R.id.title,
            FontSizeUtils.updateFontSize(item, R.id.empty_text,
                    R.dimen.qs_detail_item_primary_text_size);
            FontSizeUtils.updateFontSize(item, android.R.id.summary,
                    R.dimen.qs_detail_item_secondary_text_size);
            FontSizeUtils.updateFontSize(item, android.R.id.title,
                    R.dimen.qs_detail_header_text_size);
        }
    }

    public void setTitle(int title) {
            mTitle.setText(title);
    }

    public void setEmptyState(String text) {
        mEmpty.post(() -> {
        mEmptyText.setText(text);
        });
    }

    @Override
@@ -176,11 +179,6 @@ public class OutputChooserLayout extends FrameLayout {
            } else {
                iv.setImageResource(item.iconResId);
            }
            iv.getOverlay().clear();
            if (item.overlay != null) {
                item.overlay.setBounds(0, 0, mQsDetailIconOverlaySize, mQsDetailIconOverlaySize);
                iv.getOverlay().add(item.overlay);
            }
            final TextView title = view.findViewById(android.R.id.title);
            title.setText(item.line1);
            final TextView summary =  view.findViewById(android.R.id.summary);
Loading