/*
|
* 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 com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
|
|
import android.content.Context;
|
import android.content.Intent;
|
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 androidx.annotation.VisibleForTesting;
|
|
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 javax.inject.Inject;
|
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";
|
/**
|
* 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 View[] mCarrierDividers = new View[SIM_SLOTS - 1];
|
private QSCarrier[] mCarrierGroups = new QSCarrier[SIM_SLOTS];
|
private final CellSignalState[] mInfos = new CellSignalState[SIM_SLOTS];
|
private CarrierTextController mCarrierTextController;
|
private ActivityStarter mActivityStarter;
|
|
private boolean mListening;
|
|
@Inject
|
public QSCarrierGroup(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
|
NetworkController networkController, ActivityStarter activityStarter) {
|
super(context, attrs);
|
mNetworkController = networkController;
|
mActivityStarter = activityStarter;
|
}
|
|
@VisibleForTesting
|
public QSCarrierGroup(Context context, AttributeSet attrs) {
|
this(context, attrs,
|
Dependency.get(NetworkController.class),
|
Dependency.get(ActivityStarter.class));
|
}
|
|
@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);
|
|
for (int i = 0; i < SIM_SLOTS; i++) {
|
mInfos[i] = new CellSignalState();
|
mCarrierGroups[i].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;
|
updateListeners();
|
}
|
|
@Override
|
@VisibleForTesting
|
public void onDetachedFromWindow() {
|
setListening(false);
|
super.onDetachedFromWindow();
|
}
|
|
private void updateListeners() {
|
if (mListening) {
|
if (mNetworkController.hasVoiceCallingFeature()) {
|
mNetworkController.addCallback(this);
|
}
|
mCarrierTextController.setListening(this);
|
} else {
|
mNetworkController.removeCallback(this);
|
mCarrierTextController.setListening(null);
|
}
|
}
|
|
private void handleUpdateState() {
|
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);
|
}
|
|
@Override
|
public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
|
if (info.airplaneMode) {
|
setVisibility(View.GONE);
|
} else {
|
setVisibility(View.VISIBLE);
|
if (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 {
|
mInfos[0].visible = false;
|
mCarrierGroups[0].setCarrierText(info.carrierText);
|
mCarrierGroups[0].setVisibility(View.VISIBLE);
|
for (int i = 1; i < SIM_SLOTS; i++) {
|
mInfos[i].visible = false;
|
mCarrierGroups[i].setCarrierText("");
|
mCarrierGroups[i].setVisibility(View.GONE);
|
}
|
}
|
}
|
handleUpdateState();
|
}
|
|
@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;
|
handleUpdateState();
|
}
|
|
@Override
|
public void setNoSims(boolean hasNoSims, boolean simDetected) {
|
if (hasNoSims) {
|
for (int i = 0; i < SIM_SLOTS; i++) {
|
mInfos[i].visible = false;
|
}
|
}
|
handleUpdateState();
|
}
|
|
static final class CellSignalState {
|
boolean visible;
|
int mobileSignalIconId;
|
String contentDescription;
|
String typeContentDescription;
|
boolean roaming;
|
}
|
}
|