Properly check for changes in CellSignalState

Make the CellSignalState class immutable. Provide a method for changing
the visibility from Java (by providing a copy if it actually changes).

Test: atest
Test: manual
Fixes: 148957619
Change-Id: If2070113bc379a53c207f4ca94dc1f741c608386
This commit is contained in:
Fabian Kozynski
2020-02-15 19:58:10 -05:00
parent ca854b42fd
commit 00afd49556
11 changed files with 203 additions and 56 deletions

View File

@@ -14,7 +14,7 @@
~ limitations under the License
-->
<com.android.systemui.qs.QSCarrier
<com.android.systemui.qs.carrier.QSCarrier
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linear_carrier"
android:layout_width="wrap_content"
@@ -46,4 +46,4 @@
android:singleLine="true"
android:maxEms="7"/>
</com.android.systemui.qs.QSCarrier>
</com.android.systemui.qs.carrier.QSCarrier>

View File

@@ -15,7 +15,7 @@
-->
<!-- Extends LinearLayout -->
<com.android.systemui.qs.QSCarrierGroup
<com.android.systemui.qs.carrier.QSCarrierGroup
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/qs_mobile"
android:layout_width="0dp"
@@ -71,4 +71,4 @@
android:layout_weight="1"
android:visibility="gone"/>
</com.android.systemui.qs.QSCarrierGroup>
</com.android.systemui.qs.carrier.QSCarrierGroup>

View File

@@ -60,6 +60,7 @@ import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.qs.QSDetail.Callback;
import com.android.systemui.qs.carrier.QSCarrierGroup;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;

View File

@@ -17,6 +17,7 @@
package com.android.systemui.qs;
import com.android.systemui.R;
import com.android.systemui.qs.carrier.QSCarrierGroupController;
import javax.inject.Inject;

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2020 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.carrier
/**
* Represents the state of cell signal for a particular slot.
*
* To be used between [QSCarrierGroupController] and [QSCarrier].
*/
data class CellSignalState(
@JvmField val visible: Boolean = false,
@JvmField val mobileSignalIconId: Int = 0,
@JvmField val contentDescription: String? = null,
@JvmField val typeContentDescription: String? = null,
@JvmField val roaming: Boolean = false
) {
/**
* Changes the visibility of this state by returning a copy with the visibility changed.
*
* If the visibility would not change, the same state is returned.
*
* @param visible the new visibility state
* @return `this` if `this.visible == visible`. Else, a new copy with the visibility changed.
*/
fun changeVisibility(visible: Boolean): CellSignalState {
if (this.visible == visible) return this
else return copy(visible = visible)
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 The Android Open Source Project
* Copyright (C) 2020 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.systemui.qs;
package com.android.systemui.qs.carrier;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -29,6 +29,7 @@ import com.android.settingslib.Utils;
import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.DualToneHandler;
import com.android.systemui.R;
import com.android.systemui.qs.QuickStatusBarHeader;
import java.util.Objects;
@@ -41,7 +42,7 @@ public class QSCarrier extends LinearLayout {
private DualToneHandler mDualToneHandler;
private ColorStateList mColorForegroundStateList;
private float mColorForegroundIntensity;
private QSCarrierGroupController.CellSignalState mLastSignalState;
private CellSignalState mLastSignalState;
public QSCarrier(Context context) {
super(context);
@@ -76,8 +77,13 @@ public class QSCarrier extends LinearLayout {
mColorForegroundIntensity = QuickStatusBarHeader.getColorIntensity(colorForeground);
}
public void updateState(QSCarrierGroupController.CellSignalState state) {
if (Objects.equals(state, mLastSignalState)) return;
/**
* Update the state of this view
* @param state the current state of the signal for this view
* @return true if the state was actually changed
*/
public boolean updateState(CellSignalState state) {
if (Objects.equals(state, mLastSignalState)) return false;
mLastSignalState = state;
mMobileGroup.setVisibility(state.visible ? View.VISIBLE : View.GONE);
if (state.visible) {
@@ -103,6 +109,7 @@ public class QSCarrier extends LinearLayout {
}
mMobileSignal.setContentDescription(contentDescription);
}
return true;
}
private boolean hasValidTypeContentDescription(String typeContentDescription) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 The Android Open Source Project
* Copyright (C) 2020 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.systemui.qs;
package com.android.systemui.qs.carrier;
import android.content.Context;
import android.util.AttributeSet;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 The Android Open Source Project
* Copyright (C) 2020 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.systemui.qs;
package com.android.systemui.qs.carrier;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
@@ -29,7 +29,6 @@ import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.keyguard.CarrierTextController;
@@ -38,7 +37,6 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.NetworkController;
import java.util.Objects;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -82,11 +80,13 @@ public class QSCarrierGroupController {
Log.e(TAG, "Invalid SIM slot index for subscription: " + subId);
return;
}
mInfos[slotIndex].visible = statusIcon.visible;
mInfos[slotIndex].mobileSignalIconId = statusIcon.icon;
mInfos[slotIndex].contentDescription = statusIcon.contentDescription;
mInfos[slotIndex].typeContentDescription = typeContentDescription.toString();
mInfos[slotIndex].roaming = roaming;
mInfos[slotIndex] = new CellSignalState(
statusIcon.visible,
statusIcon.icon,
statusIcon.contentDescription,
typeContentDescription.toString(),
roaming
);
mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
}
@@ -94,7 +94,7 @@ public class QSCarrierGroupController {
public void setNoSims(boolean hasNoSims, boolean simDetected) {
if (hasNoSims) {
for (int i = 0; i < SIM_SLOTS; i++) {
mInfos[i].visible = false;
mInfos[i] = mInfos[i].changeVisibility(false);
}
}
mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
@@ -236,7 +236,7 @@ public class QSCarrierGroupController {
+ info.subscriptionIds[i]);
continue;
}
mInfos[slot].visible = true;
mInfos[slot] = mInfos[slot].changeVisibility(true);
slotSeen[slot] = true;
mCarrierGroups[slot].setCarrierText(
info.listOfCarriers[i].toString().trim());
@@ -244,7 +244,7 @@ public class QSCarrierGroupController {
}
for (int i = 0; i < SIM_SLOTS; i++) {
if (!slotSeen[i]) {
mInfos[i].visible = false;
mInfos[i] = mInfos[i].changeVisibility(false);
mCarrierGroups[i].setVisibility(View.GONE);
}
}
@@ -255,7 +255,7 @@ public class QSCarrierGroupController {
// No sims or airplane mode (but not WFC). Do not show QSCarrierGroup, instead just show
// info.carrierText in a different view.
for (int i = 0; i < SIM_SLOTS; i++) {
mInfos[i].visible = false;
mInfos[i] = mInfos[i].changeVisibility(false);
mCarrierGroups[i].setCarrierText("");
mCarrierGroups[i].setVisibility(View.GONE);
}
@@ -295,35 +295,6 @@ public class QSCarrierGroupController {
}
}
static final class CellSignalState {
boolean visible;
int mobileSignalIconId;
String contentDescription;
String typeContentDescription;
boolean roaming;
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) return true;
if (!(obj instanceof CellSignalState)) return false;
CellSignalState other = (CellSignalState) obj;
return this.visible == other.visible
&& this.mobileSignalIconId == other.mobileSignalIconId
&& Objects.equals(this.contentDescription, other.contentDescription)
&& Objects.equals(this.typeContentDescription, other.typeContentDescription)
&& this.roaming == other.roaming;
}
@Override
public int hashCode() {
return Objects.hash(visible,
mobileSignalIconId,
contentDescription,
typeContentDescription,
roaming);
}
}
public static class Builder {
private QSCarrierGroup mView;
private final ActivityStarter mActivityStarter;
@@ -343,7 +314,7 @@ public class QSCarrierGroupController {
mCarrierTextControllerBuilder = carrierTextControllerBuilder;
}
Builder setQSCarrierGroup(QSCarrierGroup view) {
public Builder setQSCarrierGroup(QSCarrierGroup view) {
mView = view;
return this;
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2020 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.carrier
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Assert.assertNotSame
import org.junit.Assert.assertSame
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidTestingRunner::class)
@SmallTest
class CellSignalStateTest : SysuiTestCase() {
@Test
fun testChangeVisibility_sameObject() {
val c = CellSignalState()
val other = c.changeVisibility(c.visible)
assertSame(c, other)
}
@Test
fun testChangeVisibility_otherObject() {
val c = CellSignalState()
val other = c.changeVisibility(!c.visible)
assertNotSame(c, other)
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 The Android Open Source Project
* Copyright (C) 2020 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.systemui.qs;
package com.android.systemui.qs.carrier;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2020 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.carrier;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.LayoutInflater;
import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class QSCarrierTest extends SysuiTestCase {
private QSCarrier mQSCarrier;
private TestableLooper mTestableLooper;
@Before
public void setUp() throws Exception {
mTestableLooper = TestableLooper.get(this);
LayoutInflater inflater = LayoutInflater.from(mContext);
mTestableLooper.runWithLooper(() ->
mQSCarrier = (QSCarrier) inflater.inflate(R.layout.qs_carrier, null));
}
@Test
public void testUpdateState_first() {
CellSignalState c = new CellSignalState(true, 0, "", "", false);
assertTrue(mQSCarrier.updateState(c));
}
@Test
public void testUpdateState_same() {
CellSignalState c = new CellSignalState(true, 0, "", "", false);
assertTrue(mQSCarrier.updateState(c));
assertFalse(mQSCarrier.updateState(c));
}
@Test
public void testUpdateState_changed() {
CellSignalState c = new CellSignalState(true, 0, "", "", false);
assertTrue(mQSCarrier.updateState(c));
CellSignalState other = c.changeVisibility(false);
assertTrue(mQSCarrier.updateState(other));
}
}