1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.settings.qc;
18 
19 import android.content.Context;
20 import android.graphics.Color;
21 import android.graphics.drawable.ColorDrawable;
22 import android.graphics.drawable.Drawable;
23 import android.graphics.drawable.Icon;
24 import android.graphics.drawable.LayerDrawable;
25 import android.telephony.SignalStrength;
26 import android.telephony.SubscriptionManager;
27 import android.telephony.TelephonyManager;
28 import android.util.Log;
29 import android.view.Gravity;
30 
31 import com.android.car.settings.R;
32 import com.android.car.settings.common.DrawableUtil;
33 import com.android.settingslib.Utils;
34 import com.android.settingslib.graph.SignalDrawable;
35 import com.android.settingslib.net.SignalStrengthUtil;
36 import com.android.settingslib.utils.ThreadUtils;
37 
38 import java.util.concurrent.Semaphore;
39 import java.util.concurrent.TimeUnit;
40 import java.util.concurrent.atomic.AtomicReference;
41 
42 /**
43  * Helper methods for Mobile network quick controls.
44  */
45 public class MobileNetworkQCUtils {
46     private static final String TAG = "MobileNetworkQCUtils";
47     // Timeout for acquiring a signal drawable (in ms)
48     private static final long SIGNAL_DRAWABLE_TIMEOUT = 1000L;
49     private static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);
50 
MobileNetworkQCUtils()51     private MobileNetworkQCUtils() {
52     }
53 
54     /**
55      * Retrieve an icon representing the current network symbol.
56      */
getMobileNetworkSignalIcon(Context context)57     public static Icon getMobileNetworkSignalIcon(Context context) {
58         // Set default drawable in case the SignalDrawable cannot be loaded
59         Drawable drawable = context.getDrawable(R.drawable.ic_qc_mobile_data);
60         try {
61             Semaphore lock = new Semaphore(/* permits= */0);
62             AtomicReference<Drawable> shared = new AtomicReference<>();
63             ThreadUtils.postOnMainThread(() -> {
64                 shared.set(getSignalStrengthDrawable(context));
65                 lock.release();
66             });
67             boolean success = lock.tryAcquire(SIGNAL_DRAWABLE_TIMEOUT, TimeUnit.MILLISECONDS);
68             if (success) {
69                 drawable = shared.get();
70             } else {
71                 Log.d(TAG, "Timed out getting signal drawable");
72             }
73         } catch (InterruptedException e) {
74             Log.e(TAG, "Interrupted while obtaining signal drawable", e);
75         }
76 
77         return DrawableUtil.createIconFromDrawable(drawable);
78     }
79 
getSignalStrengthDrawable(Context context)80     private static Drawable getSignalStrengthDrawable(Context context) {
81         TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
82         SignalStrength strength = telephonyManager.getSignalStrength();
83         int level = (strength == null) ? 0 : strength.getLevel();
84         int numLevels = SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
85         if (SignalStrengthUtil.shouldInflateSignalStrength(context,
86                 SubscriptionManager.getDefaultDataSubscriptionId())) {
87             level += 1;
88             numLevels += 1;
89         }
90         return createSignalDrawable(context, level, numLevels);
91     }
92 
createSignalDrawable(Context context, int level, int numLevels)93     private static Drawable createSignalDrawable(Context context, int level, int numLevels) {
94         SignalDrawable signalDrawable = new SignalDrawable(context);
95         signalDrawable.setLevel(
96                 SignalDrawable.getState(level, numLevels, /* cutOut= */ false));
97 
98         Drawable[] layers = {EMPTY_DRAWABLE, signalDrawable};
99         int iconSize = context.getResources().getDimensionPixelSize(R.dimen.icon_size);
100 
101         LayerDrawable icons = new LayerDrawable(layers);
102         // Set the network type icon at the top left
103         icons.setLayerGravity(/* index= */ 0, Gravity.TOP | Gravity.LEFT);
104         // Set the signal strength icon at the bottom right
105         icons.setLayerGravity(/* index= */ 1, Gravity.BOTTOM | Gravity.RIGHT);
106         icons.setLayerSize(/* index= */ 1, iconSize, iconSize);
107         icons.setTintList(Utils.getColorAttr(context, android.R.attr.colorControlNormal));
108         return icons;
109     }
110 }
111