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

Commit a48d2d09 authored by Fabian Kozynski's avatar Fabian Kozynski
Browse files

Extracts carrier information from QSFooterImpl

QSCarrierGroup performs the same logic and visuals that were inside
QSFooterImpl

Extracted to QSCarrier

Supports up to 3 sims

Test: atest QSFooterImpl
Test: atest QSCarrierGroup
Test: manual
Change-Id: I44e6f917e176af7f305a1de235e1a5be52da579c
parent 0506e3c7
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -14,9 +14,9 @@
  ~ limitations under the License
  -->

<LinearLayout
<com.android.systemui.qs.QSCarrier
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linear_footer_carrier"
    android:id="@+id/linear_carrier"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:orientation="horizontal"
@@ -35,7 +35,7 @@
        android:layout_marginEnd="8dp"
        android:visibility="gone" />

    <view class="com.android.systemui.qs.QSFooterImpl$QSCarrierText"
    <view class="com.android.systemui.qs.QSCarrier$QSCarrierText"
        android:id="@+id/qs_carrier_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
@@ -46,4 +46,4 @@
        android:textDirection="locale"
        android:singleLine="true" />

</LinearLayout>
 No newline at end of file
</com.android.systemui.qs.QSCarrier>
 No newline at end of file
+60 −0
Original line number Diff line number Diff line
<!--
  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
  -->

<!-- Extends LinearLayout -->
<com.android.systemui.qs.QSCarrierGroup
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/qs_mobile"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:gravity="center_vertical|start"
    android:orientation="horizontal"
    android:layout_marginEnd="32dp">

    <include
        layout="@layout/qs_carrier"
        android:id="@+id/carrier1" />

    <View
        android:id="@+id/qs_carrier_divider1"
        android:layout_width="2dp"
        android:layout_height="match_parent"
        android:layout_marginTop="15dp"
        android:layout_marginBottom="15dp"
        android:background="?android:attr/dividerVertical"
        android:visibility="gone" />

    <include
        layout="@layout/qs_carrier"
        android:id="@+id/carrier2"
        android:visibility="gone"/>

    <View
        android:id="@+id/qs_carrier_divider2"
        android:layout_width="2dp"
        android:layout_height="match_parent"
        android:layout_marginTop="15dp"
        android:layout_marginBottom="15dp"
        android:background="?android:attr/dividerVertical"
        android:visibility="gone" />

    <include
        layout="@layout/qs_carrier"
        android:id="@+id/carrier3"
        android:visibility="gone"/>

</com.android.systemui.qs.QSCarrierGroup>
 No newline at end of file
+2 −28
Original line number Diff line number Diff line
@@ -41,34 +41,8 @@
        android:layout_gravity="center_vertical"
        android:gravity="end" >

        <LinearLayout
            android:id="@+id/qs_mobile"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_vertical|start"
            android:orientation="horizontal"
            android:layout_marginEnd="32dp">

            <include
                layout="@layout/qs_footer_carrier"
                android:id="@+id/carrier1" />

            <View
                android:id="@+id/qs_carrier_divider"
                android:layout_width="2dp"
                android:layout_height="match_parent"
                android:layout_marginTop="15dp"
                android:layout_marginBottom="15dp"
                android:background="?android:attr/dividerVertical"
                android:visibility="gone" />

            <include
                layout="@layout/qs_footer_carrier"
                android:id="@+id/carrier2"
                android:visibility="gone"/>

        </LinearLayout>
        <include layout="@layout/qs_carrier_group"
        android:id="@+id/carrier_group"/>

        <com.android.systemui.qs.PageIndicator
            android:id="@+id/footer_page_indicator"
+140 −0
Original line number Diff line number Diff line
/*
 * 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 android.content.Context;
import android.content.res.ColorStateList;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.android.settingslib.Utils;
import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.R;

public class QSCarrier extends LinearLayout {

    private View mMobileGroup;
    private TextView mCarrierText;
    private ImageView mMobileSignal;
    private ImageView mMobileRoaming;
    private ColorStateList mColorForegroundStateList;
    private float mColorForegroundIntensity;

    public QSCarrier(Context context) {
        super(context);
    }

    public QSCarrier(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public QSCarrier(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public QSCarrier(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mMobileGroup = findViewById(R.id.mobile_combo);
        mMobileSignal = findViewById(R.id.mobile_signal);
        mMobileRoaming = findViewById(R.id.mobile_roaming);
        mCarrierText = findViewById(R.id.qs_carrier_text);

        int colorForeground = Utils.getColorAttrDefaultColor(mContext,
                android.R.attr.colorForeground);
        mColorForegroundStateList = ColorStateList.valueOf(colorForeground);
        mColorForegroundIntensity = QuickStatusBarHeader.getColorIntensity(colorForeground);

    }

    public void updateState(QSCarrierGroup.CellSignalState state) {
        mMobileGroup.setVisibility(state.visible ? View.VISIBLE : View.GONE);
        if (state.visible) {
            mMobileRoaming.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
            mMobileRoaming.setImageTintList(mColorForegroundStateList);
            SignalDrawable d = new SignalDrawable(mContext);
            d.setDarkIntensity(mColorForegroundIntensity);
            mMobileSignal.setImageDrawable(d);
            mMobileSignal.setImageLevel(state.mobileSignalIconId);

            StringBuilder contentDescription = new StringBuilder();
            if (state.contentDescription != null) {
                contentDescription.append(state.contentDescription).append(", ");
            }
            if (state.roaming) {
                contentDescription
                        .append(mContext.getString(R.string.data_connection_roaming))
                        .append(", ");
            }
            // TODO: show mobile data off/no internet text for 5 seconds before carrier text
            if (TextUtils.equals(state.typeContentDescription,
                    mContext.getString(R.string.data_connection_no_internet))
                    || TextUtils.equals(state.typeContentDescription,
                    mContext.getString(R.string.cell_data_off_content_description))) {
                contentDescription.append(state.typeContentDescription);
            }
            mMobileSignal.setContentDescription(contentDescription);
        }
    }

    public void setCarrierText(CharSequence text) {
        mCarrierText.setText(text);
    }

    /**
     * TextView that changes its ellipsize value with its visibility.
     */
    public static class QSCarrierText extends TextView {
        public QSCarrierText(Context context) {
            super(context);
        }

        public QSCarrierText(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        public QSCarrierText(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }

        public QSCarrierText(Context context, AttributeSet attrs, int defStyleAttr,
                int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }

        @Override
        protected void onVisibilityChanged(View changedView, int visibility) {
            super.onVisibilityChanged(changedView, visibility);
            // Only show marquee when visible
            if (visibility == VISIBLE) {
                setEllipsize(TextUtils.TruncateAt.MARQUEE);
                setSelected(true);
            } else {
                setEllipsize(TextUtils.TruncateAt.END);
                setSelected(false);
            }
        }
    }
}
+223 −0
Original line number Diff line number Diff line
/*
 * 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.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.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 {

    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 boolean mListening;

    @Inject
    public QSCarrierGroup(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
            NetworkController networkController) {
        super(context, attrs);
        mNetworkController = networkController;
    }

    @VisibleForTesting
    public QSCarrierGroup(Context context, AttributeSet attrs) {
        this(context, attrs,
                Dependency.get(NetworkController.class));
    }

    @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();
        }

        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.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;
    }
}
Loading