diff options
11 files changed, 577 insertions, 330 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index 06aba405fa3e..d66a53cd9012 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -24,6 +24,7 @@ import static com.android.systemui.DejankUtils.whitelistIpcs; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.Handler; @@ -42,11 +43,14 @@ import com.android.internal.telephony.TelephonyIntents; import com.android.settingslib.WirelessUtils; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.MainResources; import com.android.systemui.keyguard.WakefulnessLifecycle; import java.util.List; import java.util.Objects; +import javax.inject.Inject; + /** * Controller that generates text including the carrier names and/or the status of all the SIM * interfaces in the device. Through a callback, the updates can be retrieved either as a list or @@ -598,6 +602,35 @@ public class CarrierTextController { return mContext.getText(carrierHelpTextId); } + public static class Builder { + private final Context mContext; + private final String mSeparator; + private boolean mShowAirplaneMode; + private boolean mShowMissingSim; + + @Inject + public Builder(Context context, @MainResources Resources resources) { + mContext = context; + mSeparator = resources.getString( + com.android.internal.R.string.kg_text_message_separator); + } + + + public Builder setShowAirplaneMode(boolean showAirplaneMode) { + mShowAirplaneMode = showAirplaneMode; + return this; + } + + public Builder setShowMissingSim(boolean showMissingSim) { + mShowMissingSim = showMissingSim; + return this; + } + + public CarrierTextController build() { + return new CarrierTextController( + mContext, mSeparator, mShowAirplaneMode, mShowMissingSim); + } + } /** * Data structure for passing information to CarrierTextController subscribers */ diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java index 4501b8f0a469..4c7d82e99d06 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java @@ -73,7 +73,7 @@ public class QSCarrier extends LinearLayout { mColorForegroundIntensity = QuickStatusBarHeader.getColorIntensity(colorForeground); } - public void updateState(QSCarrierGroup.CellSignalState state) { + public void updateState(QSCarrierGroupController.CellSignalState state) { mMobileGroup.setVisibility(state.visible ? View.VISIBLE : View.GONE); if (state.visible) { mMobileRoaming.setVisibility(state.roaming ? View.VISIBLE : View.GONE); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java index 5742787b39bc..346c75da6a89 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java @@ -16,309 +16,43 @@ package com.android.systemui.qs; -import static com.android.systemui.Dependency.BG_HANDLER; -import static com.android.systemui.Dependency.MAIN_LOOPER; -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; -import android.util.Log; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; -import androidx.annotation.VisibleForTesting; - -import com.android.keyguard.CarrierTextController; -import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.dagger.qualifiers.BgHandler; -import com.android.systemui.dagger.qualifiers.MainLooper; -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; /** * Displays Carrier name and network status in QS */ -public class QSCarrierGroup extends LinearLayout implements - NetworkController.SignalCallback, View.OnClickListener { - - private static final String TAG = "QSCarrierGroup"; - /** - * Support up to 3 slots which is what's supported by {@link TelephonyManager#getPhoneCount} - */ - 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; - - @Inject - public QSCarrierGroup(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, - NetworkController networkController, ActivityStarter activityStarter, - @BgHandler Handler handler, - @MainLooper 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 +public class QSCarrierGroup extends LinearLayout { public QSCarrierGroup(Context context, AttributeSet attrs) { - this(context, attrs, - Dependency.get(NetworkController.class), - Dependency.get(ActivityStarter.class), - Dependency.get(BG_HANDLER), - Dependency.get(MAIN_LOOPER)); - } - - @Override - public void onClick(View v) { - if (!v.isVisibleToUser()) return; - mActivityStarter.postStartActivityDismissingKeyguard(new Intent( - Settings.ACTION_WIRELESS_SETTINGS), 0); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - mCarrierGroups[0] = findViewById(R.id.carrier1); - mCarrierGroups[1] = findViewById(R.id.carrier2); - mCarrierGroups[2] = findViewById(R.id.carrier3); - - mCarrierDividers[0] = findViewById(R.id.qs_carrier_divider1); - mCarrierDividers[1] = findViewById(R.id.qs_carrier_divider2); - - mNoSimTextView = findViewById(R.id.no_carrier_text); - - for (int i = 0; i < SIM_SLOTS; i++) { - mInfos[i] = new CellSignalState(); - mCarrierGroups[i].setOnClickListener(this); - } - mNoSimTextView.setOnClickListener(this); - - CharSequence separator = mContext.getString( - com.android.internal.R.string.kg_text_message_separator); - mCarrierTextController = new CarrierTextController(mContext, separator, false, false); - setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); - } - - public void setListening(boolean listening) { - if (listening == mListening) { - return; - } - mListening = listening; - mBgHandler.post(this::updateListeners); - } - - @Override - @VisibleForTesting - public void onDetachedFromWindow() { - setListening(false); - super.onDetachedFromWindow(); - } - - private void updateListeners() { - if (mListening) { - if (mNetworkController.hasVoiceCallingFeature()) { - mNetworkController.addCallback(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]); - } - - mCarrierDividers[0].setVisibility( - mInfos[0].visible && mInfos[1].visible ? View.VISIBLE : View.GONE); - // This tackles the case of slots 2 being available as well as at least one other. - // In that case we show the second divider. Note that if both dividers are visible, it means - // all three slots are in use, and that is correct. - mCarrierDividers[1].setVisibility( - (mInfos[1].visible && mInfos[2].visible) - || (mInfos[0].visible && mInfos[2].visible) ? View.VISIBLE : View.GONE); - } - - @VisibleForTesting - protected int getSlotIndex(int subscriptionId) { - return SubscriptionManager.getSlotIndex(subscriptionId); + super(context, attrs); } - @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]; - if (info.listOfCarriers.length == info.subscriptionIds.length) { - for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) { - int slot = getSlotIndex(info.subscriptionIds[i]); - if (slot >= SIM_SLOTS) { - Log.w(TAG, "updateInfoCarrier - slot: " + slot); - continue; - } - if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { - Log.e(TAG, - "Invalid SIM slot index for subscription: " - + info.subscriptionIds[i]); - continue; - } - mInfos[slot].visible = true; - slotSeen[slot] = true; - mCarrierGroups[slot].setCarrierText( - info.listOfCarriers[i].toString().trim()); - mCarrierGroups[slot].setVisibility(View.VISIBLE); - } - for (int i = 0; i < SIM_SLOTS; i++) { - if (!slotSeen[i]) { - mInfos[i].visible = false; - mCarrierGroups[i].setVisibility(View.GONE); - } - } - } else { - Log.e(TAG, "Carrier information arrays not of same length"); - } - } else { - // 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; - mCarrierGroups[i].setCarrierText(""); - mCarrierGroups[i].setVisibility(View.GONE); - } - mNoSimTextView.setText(info.carrierText); - mNoSimTextView.setVisibility(View.VISIBLE); - } - handleUpdateState(); // handleUpdateCarrierInfo is always called from main thread. + TextView getNoSimTextView() { + return findViewById(R.id.no_carrier_text); } - @Override - public void setMobileDataIndicators(NetworkController.IconState statusIcon, - NetworkController.IconState qsIcon, int statusType, - int qsType, boolean activityIn, boolean activityOut, - String typeContentDescription, - String description, boolean isWide, int subId, boolean roaming) { - int slotIndex = getSlotIndex(subId); - if (slotIndex >= SIM_SLOTS) { - Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex); - return; - } - if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { - 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; - mInfos[slotIndex].roaming = roaming; - mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget(); + QSCarrier getCarrier1View() { + return findViewById(R.id.carrier1); } - @Override - public void setNoSims(boolean hasNoSims, boolean simDetected) { - if (hasNoSims) { - for (int i = 0; i < SIM_SLOTS; i++) { - mInfos[i].visible = false; - } - } - mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget(); + QSCarrier getCarrier2View() { + return findViewById(R.id.carrier2); } - static final class CellSignalState { - boolean visible; - int mobileSignalIconId; - String contentDescription; - String typeContentDescription; - boolean roaming; + QSCarrier getCarrier3View() { + return findViewById(R.id.carrier3); } - 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); - } - } + View getCarrierDivider1() { + return findViewById(R.id.qs_carrier_divider1); } - 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(); - } + View getCarrierDivider2() { + return findViewById(R.id.qs_carrier_divider2); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroupController.java new file mode 100644 index 000000000000..ac94858cff27 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroupController.java @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2019 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; + +import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES; + +import android.annotation.MainThread; +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.Log; +import android.view.View; +import android.widget.TextView; + +import androidx.annotation.VisibleForTesting; + +import com.android.keyguard.CarrierTextController; +import com.android.systemui.dagger.qualifiers.BgHandler; +import com.android.systemui.dagger.qualifiers.MainLooper; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.statusbar.policy.NetworkController; + +import java.util.function.Consumer; + +import javax.inject.Inject; + +public class QSCarrierGroupController { + private static final String TAG = "QSCarrierGroup"; + + /** + * Support up to 3 slots which is what's supported by {@link TelephonyManager#getPhoneCount} + */ + private static final int SIM_SLOTS = 3; + + private final ActivityStarter mActivityStarter; + private final Handler mBgHandler; + private final NetworkController mNetworkController; + private final CarrierTextController mCarrierTextController; + private final TextView mNoSimTextView; + private final H mMainHandler; + private final Callback mCallback; + private boolean mListening; + private final CellSignalState[] mInfos = + new CellSignalState[SIM_SLOTS]; + private View[] mCarrierDividers = new View[SIM_SLOTS - 1]; + private QSCarrier[] mCarrierGroups = new QSCarrier[SIM_SLOTS]; + + private final NetworkController.SignalCallback mSignalCallback = + new NetworkController.SignalCallback() { + @Override + public void setMobileDataIndicators(NetworkController.IconState statusIcon, + NetworkController.IconState qsIcon, int statusType, int qsType, + boolean activityIn, boolean activityOut, String typeContentDescription, + String description, boolean isWide, int subId, boolean roaming) { + int slotIndex = getSlotIndex(subId); + if (slotIndex >= SIM_SLOTS) { + Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex); + return; + } + if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { + 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; + mInfos[slotIndex].roaming = roaming; + mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget(); + } + + @Override + public void setNoSims(boolean hasNoSims, boolean simDetected) { + if (hasNoSims) { + for (int i = 0; i < SIM_SLOTS; i++) { + mInfos[i].visible = false; + } + } + mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget(); + } + }; + + private static class Callback implements CarrierTextController.CarrierTextCallback { + private H mHandler; + + Callback(H handler) { + mHandler = handler; + } + + @Override + public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) { + mHandler.obtainMessage(H.MSG_UPDATE_CARRIER_INFO, info).sendToTarget(); + } + } + + private QSCarrierGroupController(QSCarrierGroup view, ActivityStarter activityStarter, + @BgHandler Handler bgHandler, @MainLooper Looper mainLooper, + NetworkController networkController, + CarrierTextController.Builder carrierTextControllerBuilder) { + mActivityStarter = activityStarter; + mBgHandler = bgHandler; + mNetworkController = networkController; + mCarrierTextController = carrierTextControllerBuilder + .setShowAirplaneMode(false) + .setShowMissingSim(false) + .build(); + + View.OnClickListener onClickListener = v -> { + if (!v.isVisibleToUser()) { + return; + } + mActivityStarter.postStartActivityDismissingKeyguard( + new Intent(Settings.ACTION_WIRELESS_SETTINGS), 0); + }; + view.setOnClickListener(onClickListener); + mNoSimTextView = view.getNoSimTextView(); + mNoSimTextView.setOnClickListener(onClickListener); + mMainHandler = new H(mainLooper, this::handleUpdateCarrierInfo, this::handleUpdateState); + mCallback = new Callback(mMainHandler); + + + mCarrierGroups[0] = view.getCarrier1View(); + mCarrierGroups[1] = view.getCarrier2View(); + mCarrierGroups[2] = view.getCarrier3View(); + + mCarrierDividers[0] = view.getCarrierDivider1(); + mCarrierDividers[1] = view.getCarrierDivider2(); + + for (int i = 0; i < SIM_SLOTS; i++) { + mInfos[i] = new CellSignalState(); + mCarrierGroups[i].setOnClickListener(onClickListener); + } + view.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + + view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + } + + @Override + public void onViewDetachedFromWindow(View v) { + setListening(false); + } + }); + } + + @VisibleForTesting + protected int getSlotIndex(int subscriptionId) { + return SubscriptionManager.getSlotIndex(subscriptionId); + } + + public void setListening(boolean listening) { + if (listening == mListening) { + return; + } + mListening = listening; + + mBgHandler.post(this::updateListeners); + } + + private void updateListeners() { + if (mListening) { + if (mNetworkController.hasVoiceCallingFeature()) { + mNetworkController.addCallback(mSignalCallback); + } + mCarrierTextController.setListening(mCallback); + } else { + mNetworkController.removeCallback(mSignalCallback); + 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]); + } + + mCarrierDividers[0].setVisibility( + mInfos[0].visible && mInfos[1].visible ? View.VISIBLE : View.GONE); + // This tackles the case of slots 2 being available as well as at least one other. + // In that case we show the second divider. Note that if both dividers are visible, it means + // all three slots are in use, and that is correct. + mCarrierDividers[1].setVisibility( + (mInfos[1].visible && mInfos[2].visible) + || (mInfos[0].visible && mInfos[2].visible) ? View.VISIBLE : View.GONE); + } + + @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]; + if (info.listOfCarriers.length == info.subscriptionIds.length) { + for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) { + int slot = getSlotIndex(info.subscriptionIds[i]); + if (slot >= SIM_SLOTS) { + Log.w(TAG, "updateInfoCarrier - slot: " + slot); + continue; + } + if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { + Log.e(TAG, + "Invalid SIM slot index for subscription: " + + info.subscriptionIds[i]); + continue; + } + mInfos[slot].visible = true; + slotSeen[slot] = true; + mCarrierGroups[slot].setCarrierText( + info.listOfCarriers[i].toString().trim()); + mCarrierGroups[slot].setVisibility(View.VISIBLE); + } + for (int i = 0; i < SIM_SLOTS; i++) { + if (!slotSeen[i]) { + mInfos[i].visible = false; + mCarrierGroups[i].setVisibility(View.GONE); + } + } + } else { + Log.e(TAG, "Carrier information arrays not of same length"); + } + } else { + // 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; + mCarrierGroups[i].setCarrierText(""); + mCarrierGroups[i].setVisibility(View.GONE); + } + mNoSimTextView.setText(info.carrierText); + mNoSimTextView.setVisibility(View.VISIBLE); + } + handleUpdateState(); // handleUpdateCarrierInfo is always called from main thread. + } + + 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); + } + } + } + + static final class CellSignalState { + boolean visible; + int mobileSignalIconId; + String contentDescription; + String typeContentDescription; + boolean roaming; + } + + public static class Builder { + private QSCarrierGroup mView; + private final ActivityStarter mActivityStarter; + private final Handler mHandler; + private final Looper mLooper; + private final NetworkController mNetworkController; + private final CarrierTextController.Builder mCarrierTextControllerBuilder; + + @Inject + public Builder(ActivityStarter activityStarter, @BgHandler Handler handler, + @MainLooper Looper looper, NetworkController networkController, + CarrierTextController.Builder carrierTextControllerBuilder) { + mActivityStarter = activityStarter; + mHandler = handler; + mLooper = looper; + mNetworkController = networkController; + mCarrierTextControllerBuilder = carrierTextControllerBuilder; + } + + Builder setQSCarrierGroup(QSCarrierGroup view) { + mView = view; + return this; + } + + public QSCarrierGroupController build() { + return new QSCarrierGroupController(mView, mActivityStarter, mHandler, mLooper, + mNetworkController, mCarrierTextControllerBuilder); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java new file mode 100644 index 000000000000..fa3328417bd6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2019 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; + +import com.android.systemui.R; + +import javax.inject.Inject; + +public class QSContainerImplController { + private final QSContainerImpl mView; + private final QuickStatusBarHeaderController mQuickStatusBarHeaderController; + + private QSContainerImplController(QSContainerImpl view, + QuickStatusBarHeaderController.Builder quickStatusBarHeaderControllerBuilder) { + mView = view; + mQuickStatusBarHeaderController = quickStatusBarHeaderControllerBuilder + .setQuickStatusBarHeader(mView.findViewById(R.id.header)).build(); + } + + public void setListening(boolean listening) { + mQuickStatusBarHeaderController.setListening(listening); + } + + public static class Builder { + private final QuickStatusBarHeaderController.Builder mQuickStatusBarHeaderControllerBuilder; + private QSContainerImpl mView; + + @Inject + public Builder( + QuickStatusBarHeaderController.Builder quickStatusBarHeaderControllerBuilder) { + mQuickStatusBarHeaderControllerBuilder = quickStatusBarHeaderControllerBuilder; + } + + public Builder setQSContainerImpl(QSContainerImpl view) { + mView = view; + return this; + } + + public QSContainerImplController build() { + return new QSContainerImplController(mView, mQuickStatusBarHeaderControllerBuilder); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index ccc836f50c7b..5b09267a9e68 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -18,7 +18,6 @@ import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; @@ -81,6 +80,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; private final InjectionInflationController mInjectionInflater; + private final QSContainerImplController.Builder mQSContainerImplControllerBuilder; private final QSTileHost mHost; private boolean mShowCollapsedOnKeyguard; private boolean mLastKeyguardAndExpanded; @@ -90,15 +90,16 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca * during state transitions which often call into us. */ private int mState; + private QSContainerImplController mQSContainerImplController; @Inject public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler, - InjectionInflationController injectionInflater, - Context context, - QSTileHost qsTileHost, - StatusBarStateController statusBarStateController, CommandQueue commandQueue) { + InjectionInflationController injectionInflater, QSTileHost qsTileHost, + StatusBarStateController statusBarStateController, CommandQueue commandQueue, + QSContainerImplController.Builder qsContainerImplControllerBuilder) { mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler; mInjectionInflater = injectionInflater; + mQSContainerImplControllerBuilder = qsContainerImplControllerBuilder; commandQueue.observe(getLifecycle(), this); mHost = qsTileHost; mStatusBarStateController = statusBarStateController; @@ -121,6 +122,11 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca mFooter = view.findViewById(R.id.qs_footer); mContainer = view.findViewById(id.quick_settings_container); + mQSContainerImplController = mQSContainerImplControllerBuilder + .setQSContainerImpl((QSContainerImpl) view) + .build(); + + mQSDetail.setQsPanel(mQSPanel, mHeader, (View) mFooter); mQSAnimator = new QSAnimator(this, mHeader.findViewById(R.id.quick_qs_panel), mQSPanel); @@ -340,6 +346,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca public void setListening(boolean listening) { if (DEBUG) Log.d(TAG, "setListening " + listening); mListening = listening; + mQSContainerImplController.setListening(listening); mHeader.setListening(listening); mFooter.setListening(listening); mQSPanel.setListening(mListening, mQsExpanded); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 19af235b4f68..02e8f5909793 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -549,7 +549,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements } mHeaderQsPanel.setListening(listening); mListening = listening; - mCarrierGroup.setListening(mListening); if (listening) { mZenController.addCallback(this); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java new file mode 100644 index 000000000000..867677a46a58 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 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; + +import com.android.systemui.R; + +import javax.inject.Inject; + +public class QuickStatusBarHeaderController { + private final QuickStatusBarHeader mView; + private final QSCarrierGroupController mQSCarrierGroupController; + + private QuickStatusBarHeaderController(QuickStatusBarHeader view, + QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) { + mView = view; + mQSCarrierGroupController = qsCarrierGroupControllerBuilder + .setQSCarrierGroup(mView.findViewById(R.id.carrier_group)) + .build(); + } + + public void setListening(boolean listening) { + mQSCarrierGroupController.setListening(listening); + // TODO: move mView.setListening logic into here. + mView.setListening(listening); + } + + + public static class Builder { + private final QSCarrierGroupController.Builder mQSCarrierGroupControllerBuilder; + private QuickStatusBarHeader mView; + + @Inject + public Builder(QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) { + mQSCarrierGroupControllerBuilder = qsCarrierGroupControllerBuilder; + } + + public Builder setQuickStatusBarHeader(QuickStatusBarHeader view) { + mView = view; + return this; + } + + public QuickStatusBarHeaderController build() { + return new QuickStatusBarHeaderController(mView, mQSCarrierGroupControllerBuilder); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java index 60d76789ff63..6976649ec497 100644 --- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java +++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java @@ -27,7 +27,6 @@ import com.android.keyguard.KeyguardClockSwitch; import com.android.keyguard.KeyguardMessageArea; import com.android.keyguard.KeyguardSliceView; import com.android.systemui.dagger.SystemUIRootComponent; -import com.android.systemui.qs.QSCarrierGroup; import com.android.systemui.qs.QSFooterImpl; import com.android.systemui.qs.QSPanel; import com.android.systemui.qs.QuickQSPanel; @@ -135,11 +134,6 @@ public class InjectionInflationController { NotificationPanelView createPanelView(); /** - * Creates the QSCarrierGroup - */ - QSCarrierGroup createQSCarrierGroup(); - - /** * Creates the Shelf. */ NotificationShelf creatNotificationShelf(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupControllerTest.java index a2a20a9538fc..1bfe1b10299b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupControllerTest.java @@ -16,7 +16,10 @@ package com.android.systemui.qs; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -24,55 +27,89 @@ import android.os.Handler; import android.telephony.SubscriptionManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; import androidx.test.filters.SmallTest; import com.android.keyguard.CarrierTextController; -import com.android.systemui.Dependency; -import com.android.systemui.R; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.utils.leaks.LeakCheckedTest; +import com.android.systemui.utils.os.FakeHandler; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; +import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest -public class QSCarrierGroupTest extends LeakCheckedTest { +public class QSCarrierGroupControllerTest extends LeakCheckedTest { - private QSCarrierGroup mCarrierGroup; + private QSCarrierGroupController mQSCarrierGroupController; + private NetworkController.SignalCallback mSignalCallback; private CarrierTextController.CarrierTextCallback mCallback; + @Mock + private QSCarrierGroup mQSCarrierGroup; + @Mock + private ActivityStarter mActivityStarter; + @Mock + private NetworkController mNetworkController; + @Mock + private CarrierTextController.Builder mCarrierTextControllerBuilder; + @Mock + private CarrierTextController mCarrierTextController; private TestableLooper mTestableLooper; @Before public void setup() throws Exception { + MockitoAnnotations.initMocks(this); injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); 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(); + Handler handler = new FakeHandler(TestableLooper.get(this).getLooper()); + + when(mNetworkController.hasVoiceCallingFeature()).thenReturn(true); + doAnswer(invocation -> mSignalCallback = invocation.getArgument(0)) + .when(mNetworkController) + .addCallback(any(NetworkController.SignalCallback.class)); + + when(mCarrierTextControllerBuilder.setShowAirplaneMode(anyBoolean())) + .thenReturn(mCarrierTextControllerBuilder); + when(mCarrierTextControllerBuilder.setShowMissingSim(anyBoolean())) + .thenReturn(mCarrierTextControllerBuilder); + when(mCarrierTextControllerBuilder.build()).thenReturn(mCarrierTextController); + + doAnswer(invocation -> mCallback = invocation.getArgument(0)) + .when(mCarrierTextController) + .setListening(any(CarrierTextController.CarrierTextCallback.class)); + + when(mQSCarrierGroup.getNoSimTextView()).thenReturn(new TextView(mContext)); + when(mQSCarrierGroup.getCarrier1View()).thenReturn(mock(QSCarrier.class)); + when(mQSCarrierGroup.getCarrier2View()).thenReturn(mock(QSCarrier.class)); + when(mQSCarrierGroup.getCarrier3View()).thenReturn(mock(QSCarrier.class)); + when(mQSCarrierGroup.getCarrierDivider1()).thenReturn(new View(mContext)); + when(mQSCarrierGroup.getCarrierDivider2()).thenReturn(new View(mContext)); + + mQSCarrierGroupController = new QSCarrierGroupController.Builder( + mActivityStarter, handler, TestableLooper.get(this).getLooper(), + mNetworkController, mCarrierTextControllerBuilder) + .setQSCarrierGroup(mQSCarrierGroup) + .build(); + + mQSCarrierGroupController.setListening(true); } @Test // throws no Exception public void testUpdateCarrierText_sameLengths() { - QSCarrierGroup spiedCarrierGroup = Mockito.spy(mCarrierGroup); - when(spiedCarrierGroup.getSlotIndex(anyInt())).thenAnswer( - new Answer<Integer>() { - @Override - public Integer answer(InvocationOnMock invocationOnMock) throws Throwable { - return invocationOnMock.getArgument(0); - } - }); + QSCarrierGroupController spiedCarrierGroupController = + Mockito.spy(mQSCarrierGroupController); + when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenAnswer( + (Answer<Integer>) invocationOnMock -> invocationOnMock.getArgument(0)); // listOfCarriers length 1, subscriptionIds length 1, anySims false CarrierTextController.CarrierTextCallbackInfo @@ -115,14 +152,10 @@ public class QSCarrierGroupTest extends LeakCheckedTest { @Test // throws no Exception public void testUpdateCarrierText_differentLength() { - QSCarrierGroup spiedCarrierGroup = Mockito.spy(mCarrierGroup); - when(spiedCarrierGroup.getSlotIndex(anyInt())).thenAnswer( - new Answer<Integer>() { - @Override - public Integer answer(InvocationOnMock invocationOnMock) throws Throwable { - return invocationOnMock.getArgument(0); - } - }); + QSCarrierGroupController spiedCarrierGroupController = + Mockito.spy(mQSCarrierGroupController); + when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenAnswer( + (Answer<Integer>) invocationOnMock -> invocationOnMock.getArgument(0)); // listOfCarriers length 2, subscriptionIds length 1, anySims false CarrierTextController.CarrierTextCallbackInfo @@ -164,9 +197,11 @@ public class QSCarrierGroupTest extends LeakCheckedTest { @Test // throws no Exception public void testUpdateCarrierText_invalidSim() { - QSCarrierGroup spiedCarrierGroup = Mockito.spy(mCarrierGroup); - when(spiedCarrierGroup.getSlotIndex(anyInt())).thenReturn( + QSCarrierGroupController spiedCarrierGroupController = + Mockito.spy(mQSCarrierGroupController); + when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenReturn( SubscriptionManager.INVALID_SIM_SLOT_INDEX); + CarrierTextController.CarrierTextCallbackInfo c4 = new CarrierTextController.CarrierTextCallbackInfo( "", @@ -179,10 +214,7 @@ public class QSCarrierGroupTest extends LeakCheckedTest { @Test // throws no Exception public void testSetMobileDataIndicators_invalidSim() { - QSCarrierGroup spiedCarrierGroup = Mockito.spy(mCarrierGroup); - when(spiedCarrierGroup.getSlotIndex(anyInt())).thenReturn( - SubscriptionManager.INVALID_SIM_SLOT_INDEX); - spiedCarrierGroup.setMobileDataIndicators( + mSignalCallback.setMobileDataIndicators( mock(NetworkController.IconState.class), mock(NetworkController.IconState.class), 0, 0, true, true, "", "", true, 0, true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index 6cebb1206efe..800456228e84 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -147,9 +147,9 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { new RemoteInputQuickSettingsDisabler(context, mock(ConfigurationController.class), commandQueue), new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()), - context, mock(QSTileHost.class), mock(StatusBarStateController.class), - commandQueue); + commandQueue, + mock(QSContainerImplController.Builder.class)); } } |