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

Commit dc2db5a7 authored by Jorge Ruesga's avatar Jorge Ruesga Committed by Gerrit Code Review
Browse files

base: dynamic tiles

Add support for dynamic tiles

Video: https://cloud.ruesga.com/f/71a12e4801/


Required: topic:customtiles_respkg
          topic:readd_customtiles
JIRA: CML-22

Change-Id: Ie17ebf09ee88bc0c53561decc27430e174814543
Signed-off-by: default avatarJorge Ruesga <jorge@ruesga.com>
parent 1fc5382c
Loading
Loading
Loading
Loading
+44 −29
Original line number Diff line number Diff line
@@ -51,37 +51,52 @@ public class QSConstants {
    public static final String TILE_AMBIENT_DISPLAY = "ambient_display";
    public static final String TILE_SYNC = "sync";

    public static final String DYNAMIC_TILE_NEXT_ALARM = "next_alarm";
    public static final String DYNAMIC_TILE_IME_SELECTOR = "ime_selector";
    public static final String DYNAMIC_TILE_SU = "su";
    public static final String DYNAMIC_TILE_ADB = "adb";

    protected static final ArrayList<String> STATIC_TILES_AVAILABLE = new ArrayList<String>();
    protected static final ArrayList<String> DYNAMIC_TILES_AVAILABLE = new ArrayList<String>();
    protected static final ArrayList<String> TILES_AVAILABLE = new ArrayList<String>();

    static {
        TILES_AVAILABLE.add(TILE_WIFI);
        TILES_AVAILABLE.add(TILE_BLUETOOTH);
        TILES_AVAILABLE.add(TILE_CELLULAR);
        TILES_AVAILABLE.add(TILE_AIRPLANE);
        TILES_AVAILABLE.add(TILE_ROTATION);
        TILES_AVAILABLE.add(TILE_FLASHLIGHT);
        TILES_AVAILABLE.add(TILE_LOCATION);
        TILES_AVAILABLE.add(TILE_CAST);
        TILES_AVAILABLE.add(TILE_INVERSION);
        TILES_AVAILABLE.add(TILE_HOTSPOT);
        TILES_AVAILABLE.add(TILE_NOTIFICATIONS);
        TILES_AVAILABLE.add(TILE_DATA);
        TILES_AVAILABLE.add(TILE_ROAMING);
        TILES_AVAILABLE.add(TILE_DDS);
        TILES_AVAILABLE.add(TILE_APN);
        TILES_AVAILABLE.add(TILE_PROFILES);
        TILES_AVAILABLE.add(TILE_PERFORMANCE);
        TILES_AVAILABLE.add(TILE_ADB_NETWORK);
        TILES_AVAILABLE.add(TILE_NFC);
        TILES_AVAILABLE.add(TILE_COMPASS);
        TILES_AVAILABLE.add(TILE_LOCKSCREEN);
        TILES_AVAILABLE.add(TILE_LTE);
        TILES_AVAILABLE.add(TILE_VISUALIZER);
        TILES_AVAILABLE.add(TILE_SCREEN_TIMEOUT);
        TILES_AVAILABLE.add(TILE_LIVE_DISPLAY);
        TILES_AVAILABLE.add(TILE_USB_TETHER);
        TILES_AVAILABLE.add(TILE_HEADS_UP);
        TILES_AVAILABLE.add(TILE_AMBIENT_DISPLAY);
        TILES_AVAILABLE.add(TILE_SYNC);
        STATIC_TILES_AVAILABLE.add(TILE_WIFI);
        STATIC_TILES_AVAILABLE.add(TILE_BLUETOOTH);
        STATIC_TILES_AVAILABLE.add(TILE_CELLULAR);
        STATIC_TILES_AVAILABLE.add(TILE_AIRPLANE);
        STATIC_TILES_AVAILABLE.add(TILE_ROTATION);
        STATIC_TILES_AVAILABLE.add(TILE_FLASHLIGHT);
        STATIC_TILES_AVAILABLE.add(TILE_LOCATION);
        STATIC_TILES_AVAILABLE.add(TILE_CAST);
        STATIC_TILES_AVAILABLE.add(TILE_INVERSION);
        STATIC_TILES_AVAILABLE.add(TILE_HOTSPOT);
        STATIC_TILES_AVAILABLE.add(TILE_NOTIFICATIONS);
        STATIC_TILES_AVAILABLE.add(TILE_DATA);
        STATIC_TILES_AVAILABLE.add(TILE_ROAMING);
        STATIC_TILES_AVAILABLE.add(TILE_DDS);
        STATIC_TILES_AVAILABLE.add(TILE_APN);
        STATIC_TILES_AVAILABLE.add(TILE_PROFILES);
        STATIC_TILES_AVAILABLE.add(TILE_PERFORMANCE);
        STATIC_TILES_AVAILABLE.add(TILE_ADB_NETWORK);
        STATIC_TILES_AVAILABLE.add(TILE_NFC);
        STATIC_TILES_AVAILABLE.add(TILE_COMPASS);
        STATIC_TILES_AVAILABLE.add(TILE_LOCKSCREEN);
        STATIC_TILES_AVAILABLE.add(TILE_LTE);
        STATIC_TILES_AVAILABLE.add(TILE_VISUALIZER);
        STATIC_TILES_AVAILABLE.add(TILE_SCREEN_TIMEOUT);
        STATIC_TILES_AVAILABLE.add(TILE_LIVE_DISPLAY);
        STATIC_TILES_AVAILABLE.add(TILE_USB_TETHER);
        STATIC_TILES_AVAILABLE.add(TILE_HEADS_UP);
        STATIC_TILES_AVAILABLE.add(TILE_AMBIENT_DISPLAY);
        STATIC_TILES_AVAILABLE.add(TILE_SYNC);

        DYNAMIC_TILES_AVAILABLE.add(DYNAMIC_TILE_NEXT_ALARM);
        DYNAMIC_TILES_AVAILABLE.add(DYNAMIC_TILE_IME_SELECTOR);
        DYNAMIC_TILES_AVAILABLE.add(DYNAMIC_TILE_SU);
        DYNAMIC_TILES_AVAILABLE.add(DYNAMIC_TILE_ADB);

        TILES_AVAILABLE.addAll(STATIC_TILES_AVAILABLE);
        TILES_AVAILABLE.addAll(DYNAMIC_TILES_AVAILABLE);
    }
}
+120 −1
Original line number Diff line number Diff line
@@ -17,30 +17,52 @@
package com.android.internal.util.cm;

import android.bluetooth.BluetoothAdapter;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.net.ConnectivityManager;
import android.nfc.NfcAdapter;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.SparseArray;

import com.android.internal.telephony.PhoneConstants;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

public class QSUtils {
    private static boolean sAvailableTilesFiltered;
    private static final SparseArray<Context> sSystemUiContextForUser = new SparseArray<>();

    public interface OnQSChanged {
        void onQSChanged();
    }

    private QSUtils() {}

    public static boolean isStaticQsTile(String tileSpec) {
        return QSConstants.STATIC_TILES_AVAILABLE.contains(tileSpec);
    }

    public static boolean isDynamicQsTile(String tileSpec) {
        return QSConstants.DYNAMIC_TILES_AVAILABLE.contains(tileSpec);
    }

    public static List<String> getAvailableTiles(Context context) {
        filterTiles(context);
        return QSConstants.TILES_AVAILABLE;
@@ -102,6 +124,10 @@ public class QSUtils {
                case QSConstants.TILE_AMBIENT_DISPLAY:
                    removeTile = !deviceSupportsDoze(context);
                    break;

                case QSConstants.DYNAMIC_TILE_SU:
                    removeTile = !supportsRootAccess();
                    break;
            }
            if (removeTile) {
                iterator.remove();
@@ -116,6 +142,95 @@ public class QSUtils {
        }
    }

    public static int getDynamicQSTileResIconId(Context context, int userId, String tileSpec) {
        Context ctx = getQSTileContext(context, userId);
        int index = translateDynamicQsTileSpecToIndex(ctx, tileSpec);
        if (index == -1) {
            return 0;
        }

        try {
            String resourceName = ctx.getResources().getStringArray(
                    ctx.getResources().getIdentifier("dynamic_qs_tiles_icons_resources_ids",
                            "array", ctx.getPackageName()))[index];
            return ctx.getResources().getIdentifier(
                    resourceName, "drawable", ctx.getPackageName());
        } catch (Exception ex) {
            // Ignore
        }
        return 0;
    }

    public static String getDynamicQSTileLabel(Context context, int userId, String tileSpec) {
        Context ctx = getQSTileContext(context, userId);
        int index = translateDynamicQsTileSpecToIndex(ctx, tileSpec);
        if (index == -1) {
            return null;
        }

        try {
            return ctx.getResources().getStringArray(
                    ctx.getResources().getIdentifier("dynamic_qs_tiles_labels",
                            "array", ctx.getPackageName()))[index];
        } catch (Exception ex) {
            // Ignore
        }
        return null;
    }

    private static int translateDynamicQsTileSpecToIndex(Context context, String tileSpec) {
        String[] keys = context.getResources().getStringArray(context.getResources().getIdentifier(
                "dynamic_qs_tiles_values", "array", context.getPackageName()));
        int count = keys.length;
        for (int i = 0; i < count; i++) {
            if (keys[i].equals(tileSpec)) {
                return i;
            }
        }
        return -1;
    }

    public static Context getQSTileContext(Context context, int userId) {
        Context ctx = sSystemUiContextForUser.get(userId);
        if (ctx == null) {
            try {
                ctx = context.createPackageContextAsUser(
                        "com.android.systemui", 0, new UserHandle(userId));
                sSystemUiContextForUser.put(userId, ctx);
            } catch (NameNotFoundException ex) {
                // We can safely ignore this
            }
        }
        return ctx;
    }

    public static boolean isQSTileEnabledForUser(
            Context context, String tileSpec, int userId) {
        final ContentResolver resolver = context.getContentResolver();
        String order = Settings.Secure.getStringForUser(resolver,
                Settings.Secure.QS_TILES, userId);
        return Arrays.asList(order.split(",")).contains(tileSpec);
    }

    public static ContentObserver registerObserverForQSChanges(Context ctx, final OnQSChanged cb) {
        ContentObserver observer = new ContentObserver(new Handler()) {
            @Override
            public void onChange(boolean selfChange, Uri uri) {
                cb.onQSChanged();
            }
        };

        ctx.getContentResolver().registerContentObserver(
                Settings.Secure.getUriFor(Settings.Secure.QS_TILES),
                false, observer, UserHandle.USER_ALL);
        return observer;
    }

    public static void unregisterObserverForQSChanges(Context ctx, ContentObserver observer) {
        ctx.getContentResolver().unregisterContentObserver(observer);
    }


    public static boolean deviceSupportsLte(Context ctx) {
        final TelephonyManager tm = (TelephonyManager)
                ctx.getSystemService(Context.TELEPHONY_SERVICE);
@@ -178,4 +293,8 @@ public class QSUtils {
                    com.android.internal.R.string.config_dozeComponent);
        return !TextUtils.isEmpty(name);
    }

    private static boolean supportsRootAccess() {
        return Build.IS_DEBUGGABLE || "eng".equals(Build.TYPE);
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -146,6 +146,12 @@
    <!-- USB_PREFERENCES: Notification for when no USB options chosen.  This is the title -->
    <string name="usb_choose_notification_title">Touch to choose USB options.</string>

    <!-- ADB custom tile -->
    <string name="adb_active_custom_tile">ADB - <xliff:g id="adb_type" example="Usb">%1$s</xliff:g></string>
    <string name="adb_active_custom_tile_both">Both</string>
    <string name="adb_active_custom_tile_usb">USB</string>
    <string name="adb_active_custom_tile_net">Network</string>

    <!-- Title of an application permission, listed so the user can choose whether they want the application to do this. -->
    <string name="permlab_interceptPackageLaunch">intercept app launch</string>
    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+6 −0
Original line number Diff line number Diff line
@@ -194,6 +194,12 @@
    <java-symbol type="string" name="adb_both_active_notification_title" />
    <java-symbol type="string" name="adb_active_generic_notification_message" />

    <!-- ADB custom tile -->
    <java-symbol type="string" name="adb_active_custom_tile" />
    <java-symbol type="string" name="adb_active_custom_tile_both" />
    <java-symbol type="string" name="adb_active_custom_tile_usb" />
    <java-symbol type="string" name="adb_active_custom_tile_net" />

    <java-symbol type="bool" name="config_fetch_apn_from_omh_card" />

    <!-- Theme install failure notification -->
+1 −0
Original line number Diff line number Diff line
@@ -132,6 +132,7 @@

    <!-- Quick Settings Tile Listener -->
    <uses-permission android:name="cyanogenmod.permission.BIND_CUSTOM_TILE_LISTENER_SERVICE"/>
    <uses-permission android:name="cyanogenmod.permission.PUBLISH_CUSTOM_TILE"/>

    <!-- Sync tile -->
    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
Loading