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

Commit 00ca556f authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Create special case mobile data slice"

parents 7946eee8 1138218a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2991,7 +2991,7 @@
            android:label="@string/settings_panel_title"
            android:theme="@style/Theme.BottomDialog"
            android:excludeFromRecents="true"
            android:launchMode="singleTask"
            android:launchMode="singleTop"
            android:exported="true">
                 <intent-filter>
                     <action android:name="android.settings.panel.action.INTERNET_CONNECTIVITY" />
+9 −4
Original line number Diff line number Diff line
@@ -119,6 +119,14 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon
                && mSubId == SubscriptionManager.getDefaultDataSubscriptionId();
    }

    public static Uri getObservableUri(int subId) {
        Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA);
        if (TelephonyManager.getDefault().getSimCount() != 1) {
            uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + subId);
        }
        return uri;
    }

    public void init(FragmentManager fragmentManager, int subId) {
        mFragmentManager = fragmentManager;
        mSubId = subId;
@@ -169,10 +177,7 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon
        }

        public void register(Context context, int subId) {
            Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA);
            if (TelephonyManager.getDefault().getSimCount() != 1) {
                uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + subId);
            }
            final Uri uri = getObservableUri(subId);
            context.getContentResolver().registerContentObserver(uri, false, this);

        }
+249 −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.settings.network.telephony;

import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;

import android.annotation.ColorInt;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;

import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.SliceAction;

import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.network.AirplaneModePreferenceController;
import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.slices.CustomSliceable;
import com.android.settings.slices.SliceBackgroundWorker;

import com.google.common.annotations.VisibleForTesting;

import java.io.IOException;

/**
 * Custom {@link Slice} for Mobile Data.
 * <p>
 *     We make a custom slice instead of using {@link MobileDataPreferenceController} because the
 *     pref controller is generalized across any carrier, and thus does not control a specific
 *     subscription. We attempt to reuse any telephony-specific code from the preference controller.
 *
 * </p>
 *
 */
public class MobileDataSlice implements CustomSliceable {

    private final Context mContext;
    private final SubscriptionManager mSubscriptionManager;
    private final TelephonyManager mTelephonyManager;

    public MobileDataSlice(Context context) {
        mContext = context;
        mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
        mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
    }

    @Override
    public Slice getSlice() {
        final IconCompat icon = IconCompat.createWithResource(mContext,
                R.drawable.ic_network_cell);
        final String title = mContext.getText(R.string.mobile_data_settings_title).toString();
        final CharSequence summary = getSummary();
        @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
        final PendingIntent toggleAction = getBroadcastIntent(mContext);
        final PendingIntent primaryAction = getPrimaryAction();
        final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryAction, icon,
                ListBuilder.ICON_IMAGE, title);
        final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction,
                null /* actionTitle */, isMobileDataEnabled());

        final ListBuilder listBuilder = new ListBuilder(mContext, getUri(),
                ListBuilder.INFINITY)
                .setAccentColor(color)
                .addRow(new ListBuilder.RowBuilder()
                        .setTitle(title)
                        .setSubtitle(summary)
                        .addEndItem(toggleSliceAction)
                        .setPrimaryAction(primarySliceAction));
        return listBuilder.build();
    }

    @Override
    public Uri getUri() {
        return CustomSliceRegistry.MOBILE_DATA_SLICE_URI;
    }

    @Override
    public void onNotifyChange(Intent intent) {
        // Don't make a change if we are in Airplane Mode.
        if (isAirplaneModeEnabled()) {
            return;
        }

        final boolean newState = intent.getBooleanExtra(EXTRA_TOGGLE_STATE,
                    isMobileDataEnabled());

        final int defaultSubId = getDefaultSubscriptionId(mSubscriptionManager);
        if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
            return; // No subscription - do nothing.
        }

        MobileNetworkUtils.setMobileDataEnabled(mContext, defaultSubId, newState,
                false /* disableOtherSubscriptions */);
        // Do not notifyChange on Uri. The service takes longer to update the current value than it
        // does for the Slice to check the current value again. Let {@link WifiScanWorker}
        // handle it.
    }

    @Override
    public IntentFilter getIntentFilter() {
        final IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        return filter;
    }

    @Override
    public Intent getIntent() {
        return new Intent(mContext, MobileNetworkActivity.class);
    }

    @Override
    public Class<? extends SliceBackgroundWorker> getBackgroundWorkerClass() {
        return MobileDataWorker.class;
    }

    protected static int getDefaultSubscriptionId(SubscriptionManager subscriptionManager) {
        final SubscriptionInfo defaultSubscription =
                subscriptionManager.getDefaultDataSubscriptionInfo();
        if (defaultSubscription == null) {
            return SubscriptionManager.INVALID_SUBSCRIPTION_ID; // No default subscription
        }

        return defaultSubscription.getSubscriptionId();
    }

    private CharSequence getSummary() {
        final SubscriptionInfo defaultSubscription =
                mSubscriptionManager.getDefaultDataSubscriptionInfo();
        if (defaultSubscription == null) {
            return null; // no summary text
        }

        return defaultSubscription.getDisplayName();
    }

    private PendingIntent getPrimaryAction() {
        final Intent intent = getIntent();
        return PendingIntent.getActivity(mContext, 0 /* requestCode */,
                intent, 0 /* flags */);
    }

    @VisibleForTesting
    boolean isAirplaneModeEnabled() {
        // Generic key since we only want the method check - no UI.
        AirplaneModePreferenceController controller = new AirplaneModePreferenceController(mContext,
                "key" /* Key */);
        return controller.isChecked();
    }

    @VisibleForTesting
    boolean isMobileDataEnabled() {
        if (mTelephonyManager == null) {
            return false;
        }

        return mTelephonyManager.isDataEnabled();
    }

    /**
     * Listener for mobile data state changes.
     *
     * <p>
     *     Listen to individual subscription changes since there is no framework broadcast.
     *
     *     This worker registers a ContentObserver in the background and updates the MobileData
     *     Slice when the value changes.
     */
    public static class MobileDataWorker extends SliceBackgroundWorker<Void> {

        DataContentObserver mMobileDataObserver;

        public MobileDataWorker(Context context, Uri uri) {
            super(context, uri);
            final Handler handler = new Handler(Looper.getMainLooper());
            mMobileDataObserver = new DataContentObserver(handler, this);
        }

        @Override
        protected void onSlicePinned() {
            final SubscriptionManager subscriptionManager =
                    getContext().getSystemService(SubscriptionManager.class);
            mMobileDataObserver.register(getContext(),
                    getDefaultSubscriptionId(subscriptionManager));
        }

        @Override
        protected void onSliceUnpinned() {
            mMobileDataObserver.unRegister(getContext());
        }

        @Override
        public void close() throws IOException {
            mMobileDataObserver = null;
        }

        public void updateSlice() {
            notifySliceChange();
        }

        public class DataContentObserver extends ContentObserver {

            private final MobileDataWorker mSliceBackgroundWorker;

            public DataContentObserver(Handler handler, MobileDataWorker backgroundWorker) {
                super(handler);
                mSliceBackgroundWorker = backgroundWorker;
            }

            @Override
            public void onChange(boolean selfChange) {
                mSliceBackgroundWorker.updateSlice();
            }

            public void register(Context context, int subId) {
                final Uri uri = MobileDataPreferenceController.getObservableUri(subId);
                context.getContentResolver().registerContentObserver(uri, false, this);
            }

            public void unRegister(Context context) {
                context.getContentResolver().unregisterContentObserver(this);
            }
        }
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ public class InternetConnectivityPanel implements PanelContent {
    public List<Uri> getSlices() {
        final List<Uri> uris = new ArrayList<>();
        uris.add(CustomSliceRegistry.WIFI_SLICE_URI);
        uris.add(CustomSliceRegistry.MOBILE_DATA_SLICE_URI);
        uris.add(CustomSliceRegistry.AIRPLANE_URI);
        return uris;
    }
+2 −1
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.settings.slices;

import android.content.Context;
import android.net.Uri;
import android.text.TextUtils;
import android.util.ArrayMap;

import androidx.annotation.VisibleForTesting;
@@ -35,6 +34,7 @@ import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice;
import com.android.settings.location.LocationSlice;
import com.android.settings.media.MediaOutputSlice;
import com.android.settings.network.telephony.MobileDataSlice;
import com.android.settings.wifi.slice.ContextualWifiSlice;
import com.android.settings.wifi.slice.WifiSlice;

@@ -123,6 +123,7 @@ public class CustomSliceManager {
        mUriMap.put(CustomSliceRegistry.FLASHLIGHT_SLICE_URI, FlashlightSlice.class);
        mUriMap.put(CustomSliceRegistry.LOCATION_SLICE_URI, LocationSlice.class);
        mUriMap.put(CustomSliceRegistry.LOW_STORAGE_SLICE_URI, LowStorageSlice.class);
        mUriMap.put(CustomSliceRegistry.MOBILE_DATA_SLICE_URI, MobileDataSlice.class);
        mUriMap.put(CustomSliceRegistry.NOTIFICATION_CHANNEL_SLICE_URI,
                NotificationChannelSlice.class);
        mUriMap.put(CustomSliceRegistry.STORAGE_SLICE_URI, StorageSlice.class);
Loading