Fall back to Wi-Fi data display in data usage screen with no SIM.

Bug: 70950124

Test: manual
Test: make RunSettingsRoboTests
Change-Id: I06bf78e54119819be87e15baca7e5b6a241958cb
diff --git a/src/com/android/settings/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java
index bf4da66..95a039b 100644
--- a/src/com/android/settings/SettingsPreferenceFragment.java
+++ b/src/com/android/settings/SettingsPreferenceFragment.java
@@ -375,7 +375,8 @@
         return mPreferenceCache != null ? mPreferenceCache.size() : 0;
     }
 
-    protected boolean removePreference(String key) {
+    @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+    public boolean removePreference(String key) {
         return removePreference(getPreferenceScreen(), key);
     }
 
diff --git a/src/com/android/settings/datausage/DataUsageBaseFragment.java b/src/com/android/settings/datausage/DataUsageBaseFragment.java
index 344f2b8..e9c73ff 100644
--- a/src/com/android/settings/datausage/DataUsageBaseFragment.java
+++ b/src/com/android/settings/datausage/DataUsageBaseFragment.java
@@ -48,13 +48,14 @@
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        final Context context = getActivity();
+        Context context = getContext();
 
         services.mNetworkService = INetworkManagementService.Stub.asInterface(
                 ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
         services.mStatsService = INetworkStatsService.Stub.asInterface(
                 ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
-        services.mPolicyManager = NetworkPolicyManager.from(context);
+        services.mPolicyManager = (NetworkPolicyManager)context
+                .getSystemService(Context.NETWORK_POLICY_SERVICE);
 
         services.mPolicyEditor = new NetworkPolicyEditor(services.mPolicyManager);
 
@@ -100,6 +101,7 @@
 
     /**
      * Test if device has an ethernet network connection.
+     * TODO(b/77590489): Remove this method when DataUsageSummaryLegacy is deprecated.
      */
     public boolean hasEthernet(Context context) {
         if (DataUsageUtils.TEST_RADIOS) {
diff --git a/src/com/android/settings/datausage/DataUsageSummary.java b/src/com/android/settings/datausage/DataUsageSummary.java
index b087787..02e6268 100644
--- a/src/com/android/settings/datausage/DataUsageSummary.java
+++ b/src/com/android/settings/datausage/DataUsageSummary.java
@@ -14,6 +14,7 @@
 
 package com.android.settings.datausage;
 
+import android.util.Log;
 import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
@@ -87,8 +88,7 @@
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-
-        final Context context = getContext();
+        Context context = getContext();
 
         boolean hasMobileData = DataUsageUtils.hasMobileData(context);
 
@@ -102,18 +102,21 @@
         if (!hasMobileData || !isAdmin()) {
             removePreference(KEY_RESTRICT_BACKGROUND);
         }
-        if (hasMobileData) {
-            SubscriptionInfo subInfo
-                    = services.mSubscriptionManager.getDefaultDataSubscriptionInfo();
-            if (subInfo != null) {
-                addMobileSection(subInfo.getSubscriptionId());
-            }
-        }
         boolean hasWifiRadio = DataUsageUtils.hasWifiRadio(context);
-        if (hasWifiRadio) {
+        if (hasMobileData) {
+            addMobileSection(defaultSubId);
+            if (DataUsageUtils.hasSim(context) && hasWifiRadio) {
+                // If the device has a SIM installed, the data usage section shows usage for mobile,
+                // and the WiFi section is added if there is a WiFi radio - legacy behavior.
+                addWifiSection();
+            }
+            // Do not add the WiFi section if either there is no WiFi radio (obviously) or if no
+            // SIM is installed. In the latter case the data usage section will show WiFi usage and
+            // there should be no explicit WiFi section added.
+        } else if (hasWifiRadio) {
             addWifiSection();
         }
-        if (hasEthernet(context)) {
+        if (DataUsageUtils.hasEthernet(context)) {
             addEthernetSection();
         }
         setHasOptionsMenu(true);
@@ -163,7 +166,8 @@
         return controllers;
     }
 
-    private void addMobileSection(int subId) {
+    @VisibleForTesting
+    void addMobileSection(int subId) {
         addMobileSection(subId, null);
     }
 
@@ -178,7 +182,8 @@
         }
     }
 
-    private void addWifiSection() {
+    @VisibleForTesting
+    void addWifiSection() {
         TemplatePreferenceCategory category = (TemplatePreferenceCategory)
                 inflatePreferences(R.xml.data_usage_wifi);
         category.setTemplate(NetworkTemplate.buildTemplateWifiWildcard(), 0, services);
@@ -291,17 +296,25 @@
         @Override
         public void setListening(boolean listening) {
             if (listening) {
-                TelephonyManager telephonyManager = (TelephonyManager) mActivity
-                        .getSystemService(Context.TELEPHONY_SERVICE);
-                final int simState = telephonyManager.getSimState();
-                // Note that pulling the SIM card returns UNKNOWN, not ABSENT.
-                if (simState == TelephonyManager.SIM_STATE_ABSENT
-                        || simState == TelephonyManager.SIM_STATE_UNKNOWN) {
-                    mSummaryLoader.setSummary(this, null);
-                } else {
+                if (DataUsageUtils.hasSim(mActivity)) {
                     mSummaryLoader.setSummary(this,
                             mActivity.getString(R.string.data_usage_summary_format,
                                     formatUsedData()));
+                } else {
+                    final DataUsageController.DataUsageInfo info =
+                            mDataController
+                                    .getDataUsageInfo(NetworkTemplate.buildTemplateWifiWildcard());
+
+                    if (info == null) {
+                        mSummaryLoader.setSummary(this, null);
+                    } else {
+                        final CharSequence wifiFormat = mActivity
+                                .getText(R.string.data_usage_wifi_format);
+                        final CharSequence sizeText =
+                                Formatter.formatFileSize(mActivity, info.usageLevel);
+                        mSummaryLoader.setSummary(this,
+                                TextUtils.expandTemplate(wifiFormat, sizeText));
+                    }
                 }
             }
         }
diff --git a/src/com/android/settings/datausage/DataUsageSummaryPreference.java b/src/com/android/settings/datausage/DataUsageSummaryPreference.java
index 1e90282..8fee1b4 100644
--- a/src/com/android/settings/datausage/DataUsageSummaryPreference.java
+++ b/src/com/android/settings/datausage/DataUsageSummaryPreference.java
@@ -20,6 +20,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Typeface;
+import android.net.NetworkTemplate;
+import android.os.Bundle;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceViewHolder;
 import android.text.Spannable;
@@ -34,7 +36,10 @@
 import android.widget.TextView;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.AppItem;
 import com.android.settingslib.Utils;
 import com.android.settingslib.utils.StringUtil;
 
@@ -83,6 +88,10 @@
     /** The number of bytes used since the start of the cycle. */
     private long mDataplanUse;
 
+    /** WiFi only mode */
+    private boolean mWifiMode;
+    private String mUsagePeriod;
+
     public DataUsageSummaryPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
         setLayoutResource(R.layout.data_usage_summary_preference);
@@ -130,6 +139,12 @@
         notifyChanged();
     }
 
+    void setWifiMode(boolean isWifiMode, String usagePeriod) {
+        mWifiMode = isWifiMode;
+        mUsagePeriod = usagePeriod;
+        notifyChanged();
+    }
+
     @Override
     public void onBindViewHolder(PreferenceViewHolder holder) {
         super.onBindViewHolder(holder);
@@ -149,28 +164,52 @@
         updateDataUsageLabels(holder);
 
         TextView usageTitle = (TextView) holder.findViewById(R.id.usage_title);
-        usageTitle.setVisibility(mNumPlans > 1 ? View.VISIBLE : View.GONE);
-
-        updateCycleTimeText(holder);
-
-
-        updateCarrierInfo((TextView) holder.findViewById(R.id.carrier_and_update));
-
+        TextView carrierInfo = (TextView) holder.findViewById(R.id.carrier_and_update);
         Button launchButton = (Button) holder.findViewById(R.id.launch_mdp_app_button);
-        launchButton.setOnClickListener((view) -> {
-            getContext().sendBroadcast(mLaunchIntent);
-        });
-        if (mLaunchIntent != null) {
+        TextView limitInfo = (TextView) holder.findViewById(R.id.data_limits);
+
+        if (mWifiMode) {
+            usageTitle.setText(R.string.data_usage_wifi_title);
+            usageTitle.setVisibility(View.VISIBLE);
+            TextView cycleTime = (TextView) holder.findViewById(R.id.cycle_left_time);
+            cycleTime.setText(mUsagePeriod);
+            carrierInfo.setVisibility(View.GONE);
+            limitInfo.setVisibility(View.GONE);
+
+            launchButton.setOnClickListener((view) -> {
+                launchWifiDataUsage(getContext());
+            });
+            launchButton.setText(R.string.launch_wifi_text);
             launchButton.setVisibility(View.VISIBLE);
         } else {
-            launchButton.setVisibility(View.GONE);
+            usageTitle.setVisibility(mNumPlans > 1 ? View.VISIBLE : View.GONE);
+            updateCycleTimeText(holder);
+            updateCarrierInfo(carrierInfo);
+            if (mLaunchIntent != null) {
+                launchButton.setOnClickListener((view) -> {
+                    getContext().sendBroadcast(mLaunchIntent);
+                });
+                launchButton.setVisibility(View.VISIBLE);
+            } else {
+                launchButton.setVisibility(View.GONE);
+            }
+            limitInfo.setVisibility(
+                    TextUtils.isEmpty(mLimitInfoText) ? View.GONE : View.VISIBLE);
+            limitInfo.setText(mLimitInfoText);
         }
-
-        TextView limitInfo = (TextView) holder.findViewById(R.id.data_limits);
-        limitInfo.setVisibility(TextUtils.isEmpty(mLimitInfoText) ? View.GONE : View.VISIBLE);
-        limitInfo.setText(mLimitInfoText);
     }
 
+    private static void launchWifiDataUsage(Context context) {
+        final Bundle args = new Bundle(1);
+        args.putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE,
+                NetworkTemplate.buildTemplateWifiWildcard());
+        final SubSettingLauncher launcher = new SubSettingLauncher(context)
+                .setArguments(args)
+                .setDestination(DataUsageList.class.getName())
+                .setSourceMetricsCategory(MetricsProto.MetricsEvent.VIEW_UNKNOWN);
+        launcher.setTitle(context.getString(R.string.wifi_data_usage));
+        launcher.launch();
+    }
 
     private void updateDataUsageLabels(PreferenceViewHolder holder) {
         TextView usageNumberField = (TextView) holder.findViewById(R.id.data_usage_view);
diff --git a/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java b/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java
index 55e7392..752d6fa 100644
--- a/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java
+++ b/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java
@@ -27,6 +27,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionPlan;
+import android.telephony.TelephonyManager;
 import android.text.BidiFormatter;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -183,17 +184,35 @@
 
     @Override
     public int getAvailabilityStatus() {
-        return mSubscriptionManager.getDefaultDataSubscriptionInfo() != null
-                ? AVAILABLE : DISABLED_UNSUPPORTED;
+        return DataUsageUtils.hasSim(mActivity)
+                || DataUsageUtils.hasWifiRadio(mContext) ? AVAILABLE : DISABLED_UNSUPPORTED;
     }
 
     @Override
     public void updateState(Preference preference) {
         DataUsageSummaryPreference summaryPreference = (DataUsageSummaryPreference) preference;
-        DataUsageController.DataUsageInfo info = mDataUsageController.getDataUsageInfo(
-                mDefaultTemplate);
 
-        mDataInfoController.updateDataLimit(info, mPolicyEditor.getPolicy(mDefaultTemplate));
+        final DataUsageController.DataUsageInfo info;
+        if (DataUsageUtils.hasSim(mActivity)) {
+            info = mDataUsageController.getDataUsageInfo(mDefaultTemplate);
+            mDataInfoController.updateDataLimit(info, mPolicyEditor.getPolicy(mDefaultTemplate));
+            summaryPreference.setWifiMode(/* isWifiMode */ false, /* usagePeriod */ null);
+        } else {
+            info = mDataUsageController.getDataUsageInfo(
+                    NetworkTemplate.buildTemplateWifiWildcard());
+            summaryPreference.setWifiMode(/* isWifiMode */ true, /* usagePeriod */ info.period);
+            summaryPreference.setLimitInfo(null);
+            summaryPreference.setUsageNumbers(info.usageLevel,
+                    /* dataPlanSize */ -1L,
+                    /* hasMobileData */ true);
+            summaryPreference.setChartEnabled(false);
+            summaryPreference.setUsageInfo(info.cycleEnd,
+                    /* snapshotTime */ -1L,
+                    /* carrierName */ null,
+                    /* numPlans */ 0,
+                    /* launchIntent */ null);
+            return;
+        }
 
         if (mSubscriptionManager != null) {
             refreshDataplanInfo(info);
diff --git a/src/com/android/settings/datausage/DataUsageUtils.java b/src/com/android/settings/datausage/DataUsageUtils.java
index af2d257..9c83047 100644
--- a/src/com/android/settings/datausage/DataUsageUtils.java
+++ b/src/com/android/settings/datausage/DataUsageUtils.java
@@ -14,11 +14,17 @@
 
 package com.android.settings.datausage;
 
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.INetworkStatsService;
+import android.net.INetworkStatsSession;
 import android.net.NetworkTemplate;
+import android.net.TrafficStats;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -31,11 +37,45 @@
 public final class DataUsageUtils {
     static final boolean TEST_RADIOS = false;
     static final String TEST_RADIOS_PROP = "test.radios";
+    private static final String ETHERNET = "ethernet";
 
     private DataUsageUtils() {
     }
 
     /**
+     * Test if device has an ethernet network connection.
+     */
+    public static boolean hasEthernet(Context context) {
+        if (DataUsageUtils.TEST_RADIOS) {
+            return SystemProperties.get(DataUsageUtils.TEST_RADIOS_PROP).contains(ETHERNET);
+        }
+
+        final ConnectivityManager conn = ConnectivityManager.from(context);
+        final boolean hasEthernet = conn.isNetworkSupported(ConnectivityManager.TYPE_ETHERNET);
+
+        final long ethernetBytes;
+        try {
+            INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
+                    ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+
+            INetworkStatsSession statsSession = statsService.openSession();
+            if (statsSession != null) {
+                ethernetBytes = statsSession.getSummaryForNetwork(
+                        NetworkTemplate.buildTemplateEthernet(), Long.MIN_VALUE, Long.MAX_VALUE)
+                        .getTotalBytes();
+                TrafficStats.closeQuietly(statsSession);
+            } else {
+                ethernetBytes = 0;
+            }
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+
+        // only show ethernet when both hardware present and traffic has occurred
+        return hasEthernet && ethernetBytes > 0;
+    }
+
+    /**
      * Returns whether device has mobile data.
      * TODO: This is the opposite to Utils.isWifiOnly(), it should be refactored into 1 method.
      */
@@ -53,10 +93,19 @@
             return SystemProperties.get(TEST_RADIOS_PROP).contains("wifi");
         }
 
-        ConnectivityManager connectivityManager = ConnectivityManager.from(context);
+        ConnectivityManager connectivityManager =
+                context.getSystemService(ConnectivityManager.class);
         return connectivityManager != null && connectivityManager.isNetworkSupported(TYPE_WIFI);
     }
 
+    public static boolean hasSim(Context context) {
+        TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+        final int simState = telephonyManager.getSimState();
+        // Note that pulling the SIM card returns UNKNOWN, not ABSENT.
+        return simState != TelephonyManager.SIM_STATE_ABSENT
+                && simState != TelephonyManager.SIM_STATE_UNKNOWN;
+    }
+
     /**
      * Returns the default subscription if available else returns
      * SubscriptionManager#INVALID_SUBSCRIPTION_ID