1 /*
2  * Copyright (C) 2020 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.internal.telephony.metrics;
18 
19 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
20 import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID;
21 
22 import static com.android.internal.telephony.TelephonyStatsLog.AIRPLANE_MODE;
23 
24 import android.content.Context;
25 import android.database.ContentObserver;
26 import android.net.Uri;
27 import android.os.Handler;
28 import android.os.Looper;
29 import android.os.SystemClock;
30 import android.provider.Settings;
31 import android.telephony.SubscriptionManager;
32 
33 import com.android.internal.telephony.Phone;
34 import com.android.internal.telephony.PhoneFactory;
35 import com.android.internal.telephony.TelephonyStatsLog;
36 import com.android.telephony.Rlog;
37 
38 /** Metrics for the usage of airplane mode. */
39 public class AirplaneModeStats extends ContentObserver {
40     private static final String TAG = AirplaneModeStats.class.getSimpleName();
41 
42     /** Ignore airplane mode events occurring in the first 30 seconds. */
43     private static final long GRACE_PERIOD_MILLIS = 30000L;
44 
45     /** An airplane mode toggle is considered short if under 10 seconds. */
46     private static final long SHORT_TOGGLE_MILLIS = 10000L;
47 
48     private long mLastActivationTime = 0L;
49 
50     private final Context mContext;
51     private final Uri mAirplaneModeSettingUri;
52 
AirplaneModeStats(Context context)53     public AirplaneModeStats(Context context) {
54         super(new Handler(Looper.getMainLooper()));
55 
56         mContext = context;
57         mAirplaneModeSettingUri = Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
58 
59         context.getContentResolver().registerContentObserver(mAirplaneModeSettingUri, false, this);
60     }
61 
62     @Override
onChange(boolean selfChange, Uri uri)63     public void onChange(boolean selfChange, Uri uri) {
64         if (uri.equals(mAirplaneModeSettingUri)) {
65             onAirplaneModeChanged(isAirplaneModeOn());
66         }
67     }
68 
isAirplaneModeOn()69     private boolean isAirplaneModeOn() {
70         return Settings.Global.getInt(mContext.getContentResolver(),
71                 Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
72     }
73 
74     /** Generate metrics when airplane mode is enabled or disabled. */
onAirplaneModeChanged(boolean isAirplaneModeOn)75     private void onAirplaneModeChanged(boolean isAirplaneModeOn) {
76         Rlog.d(TAG, "Airplane mode change. Value: " + isAirplaneModeOn);
77         long currentTime = SystemClock.elapsedRealtime();
78         if (currentTime < GRACE_PERIOD_MILLIS) {
79             return;
80         }
81 
82         boolean isShortToggle = calculateShortToggle(currentTime, isAirplaneModeOn);
83         int carrierId = getCarrierId();
84 
85         Rlog.d(TAG, "Airplane mode: " + isAirplaneModeOn + ", short=" + isShortToggle
86                 + ", carrierId=" + carrierId);
87         TelephonyStatsLog.write(AIRPLANE_MODE, isAirplaneModeOn, isShortToggle, carrierId);
88     }
89 
90 
91     /* Keep tracks of time and returns if it was a short toggle. */
calculateShortToggle(long currentTime, boolean isAirplaneModeOn)92     private boolean calculateShortToggle(long currentTime, boolean isAirplaneModeOn) {
93         boolean isShortToggle = false;
94         if (isAirplaneModeOn) {
95             // When airplane mode is enabled, track the time.
96             if (mLastActivationTime == 0L) {
97                 mLastActivationTime = currentTime;
98             }
99             return false;
100         } else {
101             // When airplane mode is disabled, reset the time and check if it was a short toggle.
102             long duration = currentTime - mLastActivationTime;
103             mLastActivationTime = 0L;
104             return duration > 0 && duration < SHORT_TOGGLE_MILLIS;
105         }
106     }
107 
108     /**
109      * Returns the carrier ID of the active data subscription. If this is not available,
110      * it returns the carrier ID of the first phone.
111      */
getCarrierId()112     private static int getCarrierId() {
113         int dataSubId = SubscriptionManager.getActiveDataSubscriptionId();
114         int phoneId = dataSubId != INVALID_SUBSCRIPTION_ID
115                 ? SubscriptionManager.getPhoneId(dataSubId) : 0;
116         Phone phone = PhoneFactory.getPhone(phoneId);
117         return phone != null ? phone.getCarrierId() : UNKNOWN_CARRIER_ID;
118     }
119 }
120