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

Commit dbc63bff authored by Fabian Kozynski's avatar Fabian Kozynski Committed by Android (Google) Code Review
Browse files

Merge "CastTile becomes unavailable when not connected to Wifi"

parents 8f63b172 4235b2a8
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -761,6 +761,8 @@
    <string name="quick_settings_cast_device_default_description">Ready to cast</string>
    <!-- QuickSettings: Cast detail panel, text when there are no items [CHAR LIMIT=NONE] -->
    <string name="quick_settings_cast_detail_empty_text">No devices available</string>
    <!-- QuickSettings: Cast unavailable, text when not connected to WiFi [CHAR LIMIT=NONE] -->
    <string name="quick_settings_cast_no_wifi">Wi\u2011Fi not connected</string>
    <!-- QuickSettings: Brightness dialog title [CHAR LIMIT=NONE] -->
    <string name="quick_settings_brightness_dialog_title">Brightness</string>
    <!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
@@ -1999,6 +2001,9 @@
    <!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
    <string name="accessibility_quick_settings_open_details">Open details.</string>

    <!-- accessibility label for quick settings items that are currently disabled. Must have a reason [CHAR LIMIT=NONE] -->
    <string name="accessibility_quick_settings_not_available">Unvailable due to <xliff:g name="reason" id="reason" example="Wifi not available">%s</xliff:g></string>

    <!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
    <string name="accessibility_quick_settings_open_settings">Open <xliff:g name="page" example="Bluetooth">%s</xliff:g> settings.</string>

+38 −5
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.NetworkController;

import java.util.LinkedHashMap;
import java.util.Set;
@@ -58,16 +59,18 @@ public class CastTile extends QSTileImpl<BooleanState> {
    private final CastController mController;
    private final CastDetailAdapter mDetailAdapter;
    private final KeyguardMonitor mKeyguard;
    private final NetworkController mNetworkController;
    private final Callback mCallback = new Callback();
    private final ActivityStarter mActivityStarter;
    private Dialog mDialog;
    private boolean mRegistered;
    private boolean mWifiConnected;

    public CastTile(QSHost host) {
        super(host);
        mController = Dependency.get(CastController.class);
        mDetailAdapter = new CastDetailAdapter();
        mKeyguard = Dependency.get(KeyguardMonitor.class);
        mNetworkController = Dependency.get(NetworkController.class);
        mActivityStarter = Dependency.get(ActivityStarter.class);
    }

@@ -87,10 +90,12 @@ public class CastTile extends QSTileImpl<BooleanState> {
        if (listening) {
            mController.addCallback(mCallback);
            mKeyguard.addCallback(mCallback);
            mNetworkController.addCallback(mSignalCallback);
        } else {
            mController.setDiscovering(false);
            mController.removeCallback(mCallback);
            mKeyguard.removeCallback(mCallback);
            mNetworkController.removeCallback(mSignalCallback);
        }
    }

@@ -112,6 +117,9 @@ public class CastTile extends QSTileImpl<BooleanState> {

    @Override
    protected void handleClick() {
        if (getState().state == Tile.STATE_UNAVAILABLE) {
            return;
        }
        if (mKeyguard.isSecure() && !mKeyguard.canSkipBouncer()) {
            mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
                showDetail(true);
@@ -164,13 +172,22 @@ public class CastTile extends QSTileImpl<BooleanState> {
        if (!state.value && connecting) {
            state.label = mContext.getString(R.string.quick_settings_connecting);
        }
        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
        state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_cast_on
                : R.drawable.ic_qs_cast_off);
        mDetailAdapter.updateItems(devices);
        state.expandedAccessibilityClassName = Button.class.getName();
        if (mWifiConnected) {
            state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
            state.secondaryLabel = "";
            state.contentDescription = state.contentDescription + ","
                    + mContext.getString(R.string.accessibility_quick_settings_open_details);
            state.expandedAccessibilityClassName = Button.class.getName();
        } else {
            state.state = Tile.STATE_UNAVAILABLE;
            String noWifi = mContext.getString(R.string.quick_settings_cast_no_wifi);
            state.secondaryLabel = noWifi;
            state.contentDescription = state.contentDescription + ", " + mContext.getString(
                    R.string.accessibility_quick_settings_not_available, noWifi);
        }
        mDetailAdapter.updateItems(devices);
    }

    @Override
@@ -192,6 +209,22 @@ public class CastTile extends QSTileImpl<BooleanState> {
                : mContext.getString(R.string.quick_settings_cast_device_default_name);
    }

    private final NetworkController.SignalCallback mSignalCallback =
            new NetworkController.SignalCallback() {
                @Override
                public void setWifiIndicators(boolean enabled,
                        NetworkController.IconState statusIcon,
                        NetworkController.IconState qsIcon, boolean activityIn, boolean activityOut,
                        String description, boolean isTransient, String statusLabel) {
                    // statusIcon.visible has the connected status information
                    boolean enabledAndConnected = enabled && qsIcon.visible;
                    if (enabledAndConnected != mWifiConnected) {
                        mWifiConnected = enabledAndConnected;
                        refreshState();
                    }
                }
            };

    private final class Callback implements CastController.Callback, KeyguardMonitor.Callback {
        @Override
        public void onCastDevicesChanged() {
+149 −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.qs.tiles;

import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.service.quicksettings.Tile;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;

import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.NetworkController;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.HashSet;
import java.util.Set;


@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class CastTileTest extends SysuiTestCase {

    @Mock
    private CastController mController;
    @Mock
    private ActivityStarter mActivityStarter;
    @Mock
    private KeyguardMonitor mKeyguard;
    @Mock
    private NetworkController mNetworkController;
    @Mock
    private QSTileHost mHost;
    @Mock
    NetworkController.SignalCallback mCallback;

    private TestableLooper mTestableLooper;
    private CastTile mCastTile;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        mTestableLooper = TestableLooper.get(this);

        mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
        mController = mDependency.injectMockDependency(CastController.class);
        mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
        mKeyguard = mDependency.injectMockDependency(KeyguardMonitor.class);
        mNetworkController = mDependency.injectMockDependency(NetworkController.class);

        when(mHost.getContext()).thenReturn(mContext);

        mCastTile = new CastTile(mHost);

        // We are not setting the mocks to listening, so we trigger a first refresh state to
        // set the initial state
        mCastTile.refreshState();

        mCastTile.handleSetListening(true);
        ArgumentCaptor<NetworkController.SignalCallback> signalCallbackArgumentCaptor =
                ArgumentCaptor.forClass(NetworkController.SignalCallback.class);
        verify(mNetworkController).addCallback(signalCallbackArgumentCaptor.capture());
        mCallback = signalCallbackArgumentCaptor.getValue();

    }

    @Test
    public void testStateUnavailable_wifiDisabled() {
        NetworkController.IconState qsIcon =
                new NetworkController.IconState(false, 0, "");
        mCallback.setWifiIndicators(false, mock(NetworkController.IconState.class),
                qsIcon, false,false, "",
                false, "");
        mTestableLooper.processAllMessages();

        assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
    }

    @Test
    public void testStateUnavailable_wifiNotConnected() {
        NetworkController.IconState qsIcon =
                new NetworkController.IconState(false, 0, "");
        mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
                qsIcon, false,false, "",
                false, "");
        mTestableLooper.processAllMessages();

        assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
    }

    @Test
    public void testStateActive_wifiEnabledAndCasting() {
        CastController.CastDevice device = mock(CastController.CastDevice.class);
        device.state = CastController.CastDevice.STATE_CONNECTED;
        Set<CastController.CastDevice> devices = new HashSet<>();
        devices.add(device);
        when(mController.getCastDevices()).thenReturn(devices);

        NetworkController.IconState qsIcon =
                new NetworkController.IconState(true, 0, "");
        mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
                qsIcon, false,false, "",
                false, "");
        mTestableLooper.processAllMessages();

        assertEquals(Tile.STATE_ACTIVE, mCastTile.getState().state);
    }

    @Test
    public void testStateInactive_wifiEnabledNotCasting() {
        NetworkController.IconState qsIcon =
                new NetworkController.IconState(true, 0, "");
        mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
                qsIcon, false,false, "",
                false, "");
        mTestableLooper.processAllMessages();

        assertEquals(Tile.STATE_INACTIVE, mCastTile.getState().state);
    }
}