Enforce updates in main thread in QSCarrierGroup
Move all updates to a Handler in the Main thread Test: atest QSCarrierGroup Test: change display size and font in Secondary user and observe that QS does not crash Fixes: 141187305 Change-Id: I27c7e8076dad94878ed5a3556f2983d631840b56
This commit is contained in:
@@ -18,11 +18,16 @@ package com.android.systemui.qs;
|
||||
|
||||
import static com.android.systemui.Dependency.BG_HANDLER;
|
||||
import static com.android.systemui.Dependency.BG_HANDLER_NAME;
|
||||
import static com.android.systemui.Dependency.MAIN_LOOPER;
|
||||
import static com.android.systemui.Dependency.MAIN_LOOPER_NAME;
|
||||
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
|
||||
|
||||
import android.annotation.MainThread;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.util.AttributeSet;
|
||||
@@ -39,6 +44,8 @@ import com.android.systemui.R;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.statusbar.policy.NetworkController;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
@@ -46,7 +53,6 @@ import javax.inject.Named;
|
||||
* Displays Carrier name and network status in QS
|
||||
*/
|
||||
public class QSCarrierGroup extends LinearLayout implements
|
||||
CarrierTextController.CarrierTextCallback,
|
||||
NetworkController.SignalCallback, View.OnClickListener {
|
||||
|
||||
private static final String TAG = "QSCarrierGroup";
|
||||
@@ -56,12 +62,14 @@ public class QSCarrierGroup extends LinearLayout implements
|
||||
private static final int SIM_SLOTS = 3;
|
||||
private final NetworkController mNetworkController;
|
||||
private final Handler mBgHandler;
|
||||
private final H mMainHandler;
|
||||
|
||||
private View[] mCarrierDividers = new View[SIM_SLOTS - 1];
|
||||
private QSCarrier[] mCarrierGroups = new QSCarrier[SIM_SLOTS];
|
||||
private TextView mNoSimTextView;
|
||||
private final CellSignalState[] mInfos = new CellSignalState[SIM_SLOTS];
|
||||
private CarrierTextController mCarrierTextController;
|
||||
private CarrierTextController.CarrierTextCallback mCallback;
|
||||
private ActivityStarter mActivityStarter;
|
||||
|
||||
private boolean mListening;
|
||||
@@ -69,11 +77,19 @@ public class QSCarrierGroup extends LinearLayout implements
|
||||
@Inject
|
||||
public QSCarrierGroup(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
|
||||
NetworkController networkController, ActivityStarter activityStarter,
|
||||
@Named(BG_HANDLER_NAME) Handler handler) {
|
||||
@Named(BG_HANDLER_NAME) Handler handler,
|
||||
@Named(MAIN_LOOPER_NAME) Looper looper) {
|
||||
super(context, attrs);
|
||||
mNetworkController = networkController;
|
||||
mActivityStarter = activityStarter;
|
||||
mBgHandler = handler;
|
||||
mMainHandler = new H(looper, this::handleUpdateCarrierInfo, this::handleUpdateState);
|
||||
mCallback = new Callback(mMainHandler);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected CarrierTextController.CarrierTextCallback getCallback() {
|
||||
return mCallback;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -81,7 +97,8 @@ public class QSCarrierGroup extends LinearLayout implements
|
||||
this(context, attrs,
|
||||
Dependency.get(NetworkController.class),
|
||||
Dependency.get(ActivityStarter.class),
|
||||
Dependency.get(BG_HANDLER));
|
||||
Dependency.get(BG_HANDLER),
|
||||
Dependency.get(MAIN_LOOPER));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,14 +153,20 @@ public class QSCarrierGroup extends LinearLayout implements
|
||||
if (mNetworkController.hasVoiceCallingFeature()) {
|
||||
mNetworkController.addCallback(this);
|
||||
}
|
||||
mCarrierTextController.setListening(this);
|
||||
mCarrierTextController.setListening(mCallback);
|
||||
} else {
|
||||
mNetworkController.removeCallback(this);
|
||||
mCarrierTextController.setListening(null);
|
||||
}
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private void handleUpdateState() {
|
||||
if (!mMainHandler.getLooper().isCurrentThread()) {
|
||||
mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < SIM_SLOTS; i++) {
|
||||
mCarrierGroups[i].updateState(mInfos[i]);
|
||||
}
|
||||
@@ -163,8 +186,13 @@ public class QSCarrierGroup extends LinearLayout implements
|
||||
return SubscriptionManager.getSlotIndex(subscriptionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
|
||||
@MainThread
|
||||
private void handleUpdateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
|
||||
if (!mMainHandler.getLooper().isCurrentThread()) {
|
||||
mMainHandler.obtainMessage(H.MSG_UPDATE_CARRIER_INFO, info).sendToTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
mNoSimTextView.setVisibility(View.GONE);
|
||||
if (!info.airplaneMode && info.anySimReady) {
|
||||
boolean[] slotSeen = new boolean[SIM_SLOTS];
|
||||
@@ -207,7 +235,7 @@ public class QSCarrierGroup extends LinearLayout implements
|
||||
mNoSimTextView.setText(info.carrierText);
|
||||
mNoSimTextView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
handleUpdateState();
|
||||
handleUpdateState(); // handleUpdateCarrierInfo is always called from main thread.
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -230,7 +258,7 @@ public class QSCarrierGroup extends LinearLayout implements
|
||||
mInfos[slotIndex].contentDescription = statusIcon.contentDescription;
|
||||
mInfos[slotIndex].typeContentDescription = typeContentDescription;
|
||||
mInfos[slotIndex].roaming = roaming;
|
||||
handleUpdateState();
|
||||
mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -240,7 +268,7 @@ public class QSCarrierGroup extends LinearLayout implements
|
||||
mInfos[i].visible = false;
|
||||
}
|
||||
}
|
||||
handleUpdateState();
|
||||
mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
|
||||
}
|
||||
|
||||
static final class CellSignalState {
|
||||
@@ -250,4 +278,47 @@ public class QSCarrierGroup extends LinearLayout implements
|
||||
String typeContentDescription;
|
||||
boolean roaming;
|
||||
}
|
||||
|
||||
private static class H extends Handler {
|
||||
private Consumer<CarrierTextController.CarrierTextCallbackInfo> mUpdateCarrierInfo;
|
||||
private Runnable mUpdateState;
|
||||
static final int MSG_UPDATE_CARRIER_INFO = 0;
|
||||
static final int MSG_UPDATE_STATE = 1;
|
||||
|
||||
H(Looper looper,
|
||||
Consumer<CarrierTextController.CarrierTextCallbackInfo> updateCarrierInfo,
|
||||
Runnable updateState) {
|
||||
super(looper);
|
||||
mUpdateCarrierInfo = updateCarrierInfo;
|
||||
mUpdateState = updateState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_UPDATE_CARRIER_INFO:
|
||||
mUpdateCarrierInfo.accept(
|
||||
(CarrierTextController.CarrierTextCallbackInfo) msg.obj);
|
||||
break;
|
||||
case MSG_UPDATE_STATE:
|
||||
mUpdateState.run();
|
||||
break;
|
||||
default:
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Callback implements CarrierTextController.CarrierTextCallback {
|
||||
private H mMainHandler;
|
||||
|
||||
Callback(H handler) {
|
||||
mMainHandler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
|
||||
mMainHandler.obtainMessage(H.MSG_UPDATE_CARRIER_INFO, info).sendToTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
@@ -28,6 +29,7 @@ import android.view.LayoutInflater;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.keyguard.CarrierTextController;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.policy.NetworkController;
|
||||
import com.android.systemui.utils.leaks.LeakCheckedTest;
|
||||
@@ -45,13 +47,20 @@ import org.mockito.stubbing.Answer;
|
||||
public class QSCarrierGroupTest extends LeakCheckedTest {
|
||||
|
||||
private QSCarrierGroup mCarrierGroup;
|
||||
private CarrierTextController.CarrierTextCallback mCallback;
|
||||
private TestableLooper mTestableLooper;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
|
||||
TestableLooper.get(this).runWithLooper(
|
||||
mTestableLooper = TestableLooper.get(this);
|
||||
mDependency.injectTestDependency(
|
||||
Dependency.BG_HANDLER, new Handler(mTestableLooper.getLooper()));
|
||||
mDependency.injectTestDependency(Dependency.MAIN_LOOPER, mTestableLooper.getLooper());
|
||||
mTestableLooper.runWithLooper(
|
||||
() -> mCarrierGroup = (QSCarrierGroup) LayoutInflater.from(mContext).inflate(
|
||||
R.layout.qs_carrier_group, null));
|
||||
mCallback = mCarrierGroup.getCallback();
|
||||
}
|
||||
|
||||
@Test // throws no Exception
|
||||
@@ -72,7 +81,7 @@ public class QSCarrierGroupTest extends LeakCheckedTest {
|
||||
new CharSequence[]{""},
|
||||
false,
|
||||
new int[]{0});
|
||||
spiedCarrierGroup.updateCarrierInfo(c1);
|
||||
mCallback.updateCarrierInfo(c1);
|
||||
|
||||
// listOfCarriers length 1, subscriptionIds length 1, anySims true
|
||||
CarrierTextController.CarrierTextCallbackInfo
|
||||
@@ -81,7 +90,7 @@ public class QSCarrierGroupTest extends LeakCheckedTest {
|
||||
new CharSequence[]{""},
|
||||
true,
|
||||
new int[]{0});
|
||||
spiedCarrierGroup.updateCarrierInfo(c2);
|
||||
mCallback.updateCarrierInfo(c2);
|
||||
|
||||
// listOfCarriers length 2, subscriptionIds length 2, anySims false
|
||||
CarrierTextController.CarrierTextCallbackInfo
|
||||
@@ -90,7 +99,7 @@ public class QSCarrierGroupTest extends LeakCheckedTest {
|
||||
new CharSequence[]{"", ""},
|
||||
false,
|
||||
new int[]{0, 1});
|
||||
spiedCarrierGroup.updateCarrierInfo(c3);
|
||||
mCallback.updateCarrierInfo(c3);
|
||||
|
||||
// listOfCarriers length 2, subscriptionIds length 2, anySims true
|
||||
CarrierTextController.CarrierTextCallbackInfo
|
||||
@@ -99,7 +108,9 @@ public class QSCarrierGroupTest extends LeakCheckedTest {
|
||||
new CharSequence[]{"", ""},
|
||||
true,
|
||||
new int[]{0, 1});
|
||||
spiedCarrierGroup.updateCarrierInfo(c4);
|
||||
mCallback.updateCarrierInfo(c4);
|
||||
|
||||
mTestableLooper.processAllMessages();
|
||||
}
|
||||
|
||||
@Test // throws no Exception
|
||||
@@ -120,7 +131,7 @@ public class QSCarrierGroupTest extends LeakCheckedTest {
|
||||
new CharSequence[]{"", ""},
|
||||
false,
|
||||
new int[]{0});
|
||||
spiedCarrierGroup.updateCarrierInfo(c1);
|
||||
mCallback.updateCarrierInfo(c1);
|
||||
|
||||
// listOfCarriers length 2, subscriptionIds length 1, anySims true
|
||||
CarrierTextController.CarrierTextCallbackInfo
|
||||
@@ -129,7 +140,7 @@ public class QSCarrierGroupTest extends LeakCheckedTest {
|
||||
new CharSequence[]{"", ""},
|
||||
true,
|
||||
new int[]{0});
|
||||
spiedCarrierGroup.updateCarrierInfo(c2);
|
||||
mCallback.updateCarrierInfo(c2);
|
||||
|
||||
// listOfCarriers length 1, subscriptionIds length 2, anySims false
|
||||
CarrierTextController.CarrierTextCallbackInfo
|
||||
@@ -138,7 +149,7 @@ public class QSCarrierGroupTest extends LeakCheckedTest {
|
||||
new CharSequence[]{""},
|
||||
false,
|
||||
new int[]{0, 1});
|
||||
spiedCarrierGroup.updateCarrierInfo(c3);
|
||||
mCallback.updateCarrierInfo(c3);
|
||||
|
||||
// listOfCarriers length 1, subscriptionIds length 2, anySims true
|
||||
CarrierTextController.CarrierTextCallbackInfo
|
||||
@@ -147,7 +158,8 @@ public class QSCarrierGroupTest extends LeakCheckedTest {
|
||||
new CharSequence[]{""},
|
||||
true,
|
||||
new int[]{0, 1});
|
||||
spiedCarrierGroup.updateCarrierInfo(c4);
|
||||
mCallback.updateCarrierInfo(c4);
|
||||
mTestableLooper.processAllMessages();
|
||||
}
|
||||
|
||||
@Test // throws no Exception
|
||||
@@ -161,7 +173,8 @@ public class QSCarrierGroupTest extends LeakCheckedTest {
|
||||
new CharSequence[]{"", ""},
|
||||
true,
|
||||
new int[]{0, 1});
|
||||
spiedCarrierGroup.updateCarrierInfo(c4);
|
||||
mCallback.updateCarrierInfo(c4);
|
||||
mTestableLooper.processAllMessages();
|
||||
}
|
||||
|
||||
@Test // throws no Exception
|
||||
|
||||
Reference in New Issue
Block a user