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