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

Commit fd2135a7 authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "[TNU01] Add Tethering notification updater" into rvc-dev am: b80e9d23 am: 7647b7ab

Change-Id: I9cacfff97d49af9cc3ca218ded5207529144c260
parents 421f8297 7647b7ab
Loading
Loading
Loading
Loading
+45 −0
Original line number Original line Diff line number Diff line
@@ -157,4 +157,49 @@


    <!-- ComponentName of the service used to run no ui tether provisioning. -->
    <!-- ComponentName of the service used to run no ui tether provisioning. -->
    <string translatable="false" name="config_wifi_tether_enable">com.android.settings/.wifi.tether.TetherService</string>
    <string translatable="false" name="config_wifi_tether_enable">com.android.settings/.wifi.tether.TetherService</string>

    <!-- Enable tethering notification -->
    <!-- Icons for showing tether enable notification.
         Each item should have two elements and be separated with ";".

         The first element is downstream types which is one of tethering. This element has to be
         made by WIFI, USB, BT, and OR'd with the others. Use "|" to combine multiple downstream
         types and use "," to separate each combinations. Such as

             USB|BT,WIFI|USB|BT

         The second element is icon for the item. This element has to be composed by
         <package name>:drawable/<resource name>. Such as

             1. com.android.networkstack.tethering:drawable/stat_sys_tether_general
             2. android:drawable/xxx

         So the entire string of each item would be

             USB|BT,WIFI|USB|BT;com.android.networkstack.tethering:drawable/stat_sys_tether_general

         NOTE: One config can be separated into two or more for readability. Such as

               WIFI|USB,WIFI|BT,USB|BT,WIFI|USB|BT;android:drawable/xxx

               can be separated into

               WIFI|USB;android:drawable/xxx
               WIFI|BT;android:drawable/xxx
               USB|BT;android:drawable/xxx
               WIFI|USB|BT;android:drawable/xxx

         Notification will not show if the downstream type isn't listed in array.
         Empty array means disable notifications. -->
    <!-- In AOSP, hotspot is configured to no notification by default. Because status bar has showed
         an icon on the right side already -->
    <string-array translatable="false" name="tethering_notification_icons">
        <item>USB;com.android.networkstack.tethering:drawable/stat_sys_tether_usb</item>
        <item>BT;com.android.networkstack.tethering:drawable/stat_sys_tether_bluetooth</item>
        <item>WIFI|USB,WIFI|BT,USB|BT,WIFI|USB|BT;com.android.networkstack.tethering:drawable/stat_sys_tether_general</item>
    </string-array>
    <!-- String for tether enable notification title. -->
    <string name="tethering_notification_title">@string/tethered_notification_title</string>
    <!-- String for tether enable notification message. -->
    <string name="tethering_notification_message">@string/tethered_notification_message</string>
</resources>
</resources>
+40 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <overlayable name="TetheringConfig">
    <overlayable name="TetheringConfig">
        <policy type="product|system|vendor">
        <policy type="product|system|vendor">
            <!-- Params from config.xml that can be overlaid -->
            <item type="array" name="config_tether_usb_regexs"/>
            <item type="array" name="config_tether_usb_regexs"/>
            <item type="array" name="config_tether_ncm_regexs" />
            <item type="array" name="config_tether_ncm_regexs" />
            <item type="array" name="config_tether_wifi_regexs"/>
            <item type="array" name="config_tether_wifi_regexs"/>
@@ -31,6 +32,45 @@
            <item type="string" name="config_mobile_hotspot_provision_response"/>
            <item type="string" name="config_mobile_hotspot_provision_response"/>
            <item type="integer" name="config_mobile_hotspot_provision_check_period"/>
            <item type="integer" name="config_mobile_hotspot_provision_check_period"/>
            <item type="string" name="config_wifi_tether_enable"/>
            <item type="string" name="config_wifi_tether_enable"/>
            <!-- Configuration values for TetheringNotificationUpdater -->
            <!-- Icons for showing tether enable notification.
            Each item should have two elements and be separated with ";".

            The first element is downstream types which is one of tethering. This element has to be
            made by WIFI, USB, BT, and OR'd with the others. Use "|" to combine multiple downstream
            types and use "," to separate each combinations. Such as

            USB|BT,WIFI|USB|BT

            The second element is icon for the item. This element has to be composed by
            <package name>:drawable/<resource name>. Such as

            1. com.android.networkstack.tethering:drawable/stat_sys_tether_general
            2. android:drawable/xxx

            So the entire string of each item would be

            USB|BT,WIFI|USB|BT;com.android.networkstack.tethering:drawable/stat_sys_tether_general

            NOTE: One config can be separated into two or more for readability. Such as

                  WIFI|USB,WIFI|BT,USB|BT,WIFI|USB|BT;android:drawable/xxx

                  can be separated into

                  WIFI|USB;android:drawable/xxx
                  WIFI|BT;android:drawable/xxx
                  USB|BT;android:drawable/xxx
                  WIFI|USB|BT;android:drawable/xxx

            Notification will not show if the downstream type isn't listed in array.
            Empty array means disable notifications. -->
            <item type="array" name="tethering_notification_icons"/>
            <!-- String for tether enable notification title. -->
            <item type="string" name="tethering_notification_title"/>
            <!-- String for tether enable notification message. -->
            <item type="string" name="tethering_notification_message"/>
            <!-- Params from config.xml that can be overlaid -->
        </policy>
        </policy>
    </overlayable>
    </overlayable>
</resources>
</resources>
+7 −5
Original line number Original line Diff line number Diff line
@@ -15,19 +15,21 @@
-->
-->
<resources>
<resources>
    <!-- Shown when the device is tethered -->
    <!-- Shown when the device is tethered -->
    <!-- Strings for tethered notification title [CHAR LIMIT=200] -->
    <!-- String for tethered notification title [CHAR LIMIT=200] -->
    <string name="tethered_notification_title">Tethering or hotspot active</string>
    <string name="tethered_notification_title">Tethering or hotspot active</string>
    <!-- Strings for tethered notification message [CHAR LIMIT=200] -->
    <!-- String for tethered notification message [CHAR LIMIT=200] -->
    <string name="tethered_notification_message">Tap to set up.</string>
    <string name="tethered_notification_message">Tap to set up.</string>


    <!-- This notification is shown when tethering has been disabled on a user's device.
    <!-- This notification is shown when tethering has been disabled on a user's device.
    The device is managed by the user's employer. Tethering can't be turned on unless the
    The device is managed by the user's employer. Tethering can't be turned on unless the
    IT administrator allows it. The noun "admin" is another reference for "IT administrator." -->
    IT administrator allows it. The noun "admin" is another reference for "IT administrator." -->
    <!-- Strings for tether disabling notification title [CHAR LIMIT=200] -->
    <!-- String for tether disabling notification title [CHAR LIMIT=200] -->
    <string name="disable_tether_notification_title">Tethering is disabled</string>
    <string name="disable_tether_notification_title">Tethering is disabled</string>
    <!-- Strings for tether disabling notification message [CHAR LIMIT=200] -->
    <!-- String for tether disabling notification message [CHAR LIMIT=200] -->
    <string name="disable_tether_notification_message">Contact your admin for details</string>
    <string name="disable_tether_notification_message">Contact your admin for details</string>


    <!-- Strings for tether notification channel name [CHAR LIMIT=200] -->
    <!-- This string should be consistent with the "Hotspot & tethering" text in the "Network and
    Internet" settings page. That is currently the tether_settings_title_all string. -->
    <!-- String for tether notification channel name [CHAR LIMIT=200] -->
    <string name="notification_channel_tethering_status">Hotspot &amp; tethering status</string>
    <string name="notification_channel_tethering_status">Hotspot &amp; tethering status</string>
</resources>
</resources>
 No newline at end of file
+10 −110
Original line number Original line Diff line number Diff line
@@ -59,10 +59,8 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;


import android.app.Notification;
import static com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE;
import android.app.NotificationChannel;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.usage.NetworkStatsManager;
import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothPan;
@@ -72,7 +70,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager;
import android.net.EthernetManager;
import android.net.EthernetManager;
@@ -128,7 +125,6 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.State;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.internal.util.StateMachine;
import com.android.networkstack.tethering.R;


import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.PrintWriter;
@@ -224,14 +220,13 @@ public class Tethering {
    private final ActiveDataSubIdListener mActiveDataSubIdListener;
    private final ActiveDataSubIdListener mActiveDataSubIdListener;
    private final ConnectedClientsTracker mConnectedClientsTracker;
    private final ConnectedClientsTracker mConnectedClientsTracker;
    private final TetheringThreadExecutor mExecutor;
    private final TetheringThreadExecutor mExecutor;
    private final TetheringNotificationUpdater mNotificationUpdater;
    private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
    private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
    // All the usage of mTetheringEventCallback should run in the same thread.
    // All the usage of mTetheringEventCallback should run in the same thread.
    private ITetheringEventCallback mTetheringEventCallback = null;
    private ITetheringEventCallback mTetheringEventCallback = null;


    private volatile TetheringConfiguration mConfig;
    private volatile TetheringConfiguration mConfig;
    private InterfaceSet mCurrentUpstreamIfaceSet;
    private InterfaceSet mCurrentUpstreamIfaceSet;
    private Notification.Builder mTetheredNotificationBuilder;
    private int mLastNotificationId;


    private boolean mRndisEnabled;       // track the RNDIS function enabled state
    private boolean mRndisEnabled;       // track the RNDIS function enabled state
    // True iff. WiFi tethering should be started when soft AP is ready.
    // True iff. WiFi tethering should be started when soft AP is ready.
@@ -255,6 +250,7 @@ public class Tethering {
        mContext = mDeps.getContext();
        mContext = mDeps.getContext();
        mNetd = mDeps.getINetd(mContext);
        mNetd = mDeps.getINetd(mContext);
        mLooper = mDeps.getTetheringLooper();
        mLooper = mDeps.getTetheringLooper();
        mNotificationUpdater = mDeps.getNotificationUpdater(mContext);


        mPublicSync = new Object();
        mPublicSync = new Object();


@@ -738,13 +734,10 @@ public class Tethering {
        final ArrayList<String> erroredList = new ArrayList<>();
        final ArrayList<String> erroredList = new ArrayList<>();
        final ArrayList<Integer> lastErrorList = new ArrayList<>();
        final ArrayList<Integer> lastErrorList = new ArrayList<>();


        boolean wifiTethered = false;
        boolean usbTethered = false;
        boolean bluetoothTethered = false;

        final TetheringConfiguration cfg = mConfig;
        final TetheringConfiguration cfg = mConfig;
        mTetherStatesParcel = new TetherStatesParcel();
        mTetherStatesParcel = new TetherStatesParcel();


        int downstreamTypesMask = DOWNSTREAM_NONE;
        synchronized (mPublicSync) {
        synchronized (mPublicSync) {
            for (int i = 0; i < mTetherStates.size(); i++) {
            for (int i = 0; i < mTetherStates.size(); i++) {
                TetherState tetherState = mTetherStates.valueAt(i);
                TetherState tetherState = mTetherStates.valueAt(i);
@@ -758,11 +751,11 @@ public class Tethering {
                    localOnlyList.add(iface);
                    localOnlyList.add(iface);
                } else if (tetherState.lastState == IpServer.STATE_TETHERED) {
                } else if (tetherState.lastState == IpServer.STATE_TETHERED) {
                    if (cfg.isUsb(iface)) {
                    if (cfg.isUsb(iface)) {
                        usbTethered = true;
                        downstreamTypesMask |= (1 << TETHERING_USB);
                    } else if (cfg.isWifi(iface)) {
                    } else if (cfg.isWifi(iface)) {
                        wifiTethered = true;
                        downstreamTypesMask |= (1 << TETHERING_WIFI);
                    } else if (cfg.isBluetooth(iface)) {
                    } else if (cfg.isBluetooth(iface)) {
                        bluetoothTethered = true;
                        downstreamTypesMask |= (1 << TETHERING_BLUETOOTH);
                    }
                    }
                    tetherList.add(iface);
                    tetherList.add(iface);
                }
                }
@@ -796,98 +789,7 @@ public class Tethering {
                    "error", TextUtils.join(",", erroredList)));
                    "error", TextUtils.join(",", erroredList)));
        }
        }


        if (usbTethered) {
        mNotificationUpdater.onDownstreamChanged(downstreamTypesMask);
            if (wifiTethered || bluetoothTethered) {
                showTetheredNotification(R.drawable.stat_sys_tether_general);
            } else {
                showTetheredNotification(R.drawable.stat_sys_tether_usb);
            }
        } else if (wifiTethered) {
            if (bluetoothTethered) {
                showTetheredNotification(R.drawable.stat_sys_tether_general);
            } else {
                /* We now have a status bar icon for WifiTethering, so drop the notification */
                clearTetheredNotification();
            }
        } else if (bluetoothTethered) {
            showTetheredNotification(R.drawable.stat_sys_tether_bluetooth);
        } else {
            clearTetheredNotification();
        }
    }

    private void showTetheredNotification(int id) {
        showTetheredNotification(id, true);
    }

    @VisibleForTesting
    protected void showTetheredNotification(int id, boolean tetheringOn) {
        NotificationManager notificationManager =
                (NotificationManager) mContext.createContextAsUser(UserHandle.ALL, 0)
                        .getSystemService(Context.NOTIFICATION_SERVICE);
        if (notificationManager == null) {
            return;
        }
        final NotificationChannel channel = new NotificationChannel(
                "TETHERING_STATUS",
                mContext.getResources().getString(R.string.notification_channel_tethering_status),
                NotificationManager.IMPORTANCE_LOW);
        notificationManager.createNotificationChannel(channel);

        if (mLastNotificationId != 0) {
            if (mLastNotificationId == id) {
                return;
            }
            notificationManager.cancel(null, mLastNotificationId);
            mLastNotificationId = 0;
        }

        Intent intent = new Intent();
        intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
        intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

        PendingIntent pi = PendingIntent.getActivity(
                mContext.createContextAsUser(UserHandle.CURRENT, 0), 0, intent, 0, null);

        Resources r = mContext.getResources();
        final CharSequence title;
        final CharSequence message;

        if (tetheringOn) {
            title = r.getText(R.string.tethered_notification_title);
            message = r.getText(R.string.tethered_notification_message);
        } else {
            title = r.getText(R.string.disable_tether_notification_title);
            message = r.getText(R.string.disable_tether_notification_message);
        }

        if (mTetheredNotificationBuilder == null) {
            mTetheredNotificationBuilder = new Notification.Builder(mContext, channel.getId());
            mTetheredNotificationBuilder.setWhen(0)
                    .setOngoing(true)
                    .setColor(mContext.getColor(
                            android.R.color.system_notification_accent_color))
                    .setVisibility(Notification.VISIBILITY_PUBLIC)
                    .setCategory(Notification.CATEGORY_STATUS);
        }
        mTetheredNotificationBuilder.setSmallIcon(id)
                .setContentTitle(title)
                .setContentText(message)
                .setContentIntent(pi);
        mLastNotificationId = id;

        notificationManager.notify(null, mLastNotificationId, mTetheredNotificationBuilder.build());
    }

    @VisibleForTesting
    protected void clearTetheredNotification() {
        NotificationManager notificationManager =
                (NotificationManager) mContext.createContextAsUser(UserHandle.ALL, 0)
                        .getSystemService(Context.NOTIFICATION_SERVICE);
        if (notificationManager != null && mLastNotificationId != 0) {
            notificationManager.cancel(null, mLastNotificationId);
            mLastNotificationId = 0;
        }
    }
    }


    private class StateReceiver extends BroadcastReceiver {
    private class StateReceiver extends BroadcastReceiver {
@@ -1081,12 +983,10 @@ public class Tethering {
                return;
                return;
            }
            }


            mWrapper.clearTetheredNotification();
            // TODO: Add user restrictions notification.
            final boolean isTetheringActiveOnDevice = (mWrapper.getTetheredIfaces().length != 0);
            final boolean isTetheringActiveOnDevice = (mWrapper.getTetheredIfaces().length != 0);


            if (newlyDisallowed && isTetheringActiveOnDevice) {
            if (newlyDisallowed && isTetheringActiveOnDevice) {
                mWrapper.showTetheredNotification(
                        R.drawable.stat_sys_tether_general, false);
                mWrapper.untetherAll();
                mWrapper.untetherAll();
                // TODO(b/148139325): send tetheringSupported on restriction change
                // TODO(b/148139325): send tetheringSupported on restriction change
            }
            }
+9 −0
Original line number Original line Diff line number Diff line
@@ -26,6 +26,8 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Looper;
import android.os.Looper;


import androidx.annotation.NonNull;

import com.android.internal.util.StateMachine;
import com.android.internal.util.StateMachine;


import java.util.ArrayList;
import java.util.ArrayList;
@@ -101,6 +103,13 @@ public abstract class TetheringDependencies {
                (IBinder) context.getSystemService(Context.NETD_SERVICE));
                (IBinder) context.getSystemService(Context.NETD_SERVICE));
    }
    }


    /**
     * Get a reference to the TetheringNotificationUpdater to be used by tethering.
     */
    public TetheringNotificationUpdater getNotificationUpdater(@NonNull final Context ctx) {
        return new TetheringNotificationUpdater(ctx);
    }

    /**
    /**
     * Get tethering thread looper.
     * Get tethering thread looper.
     */
     */
Loading