diff --git a/cm/res/res/values/config.xml b/cm/res/res/values/config.xml index 376327a..77d6e5d 100644 --- a/cm/res/res/values/config.xml +++ b/cm/res/res/values/config.xml @@ -63,4 +63,7 @@ false + + + wifi,bt,cell,airplane,rotation,flashlight,location,edit,cast,visualizer,hotspot,inversion,dnd,live_display diff --git a/cm/res/res/values/symbols.xml b/cm/res/res/values/symbols.xml index cf1336b..f1f101a 100644 --- a/cm/res/res/values/symbols.xml +++ b/cm/res/res/values/symbols.xml @@ -73,4 +73,7 @@ + + + diff --git a/src/java/org/cyanogenmod/internal/util/QSConstants.java b/src/java/org/cyanogenmod/internal/util/QSConstants.java new file mode 100644 index 0000000..c482a95 --- /dev/null +++ b/src/java/org/cyanogenmod/internal/util/QSConstants.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2015 The CyanogenMod 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 org.cyanogenmod.internal.util; + +import java.util.ArrayList; + +public class QSConstants { + private QSConstants() {} + + public static final String TILE_WIFI = "wifi"; + public static final String TILE_BLUETOOTH = "bt"; + public static final String TILE_INVERSION = "inversion"; + public static final String TILE_CELLULAR = "cell"; + public static final String TILE_AIRPLANE = "airplane"; + public static final String TILE_ROTATION = "rotation"; + public static final String TILE_FLASHLIGHT = "flashlight"; + public static final String TILE_LOCATION = "location"; + public static final String TILE_CAST = "cast"; + public static final String TILE_HOTSPOT = "hotspot"; + public static final String TILE_NOTIFICATIONS = "notifications"; + public static final String TILE_DATA = "data"; + public static final String TILE_ROAMING = "roaming"; + public static final String TILE_DDS = "dds"; + public static final String TILE_APN = "apn"; + public static final String TILE_PROFILES = "profiles"; + public static final String TILE_PERFORMANCE = "performance"; + public static final String TILE_ADB_NETWORK = "adb_network"; + public static final String TILE_NFC = "nfc"; + public static final String TILE_COMPASS = "compass"; + public static final String TILE_LOCKSCREEN = "lockscreen"; + public static final String TILE_LTE = "lte"; + public static final String TILE_VISUALIZER = "visualizer"; + public static final String TILE_VOLUME = "volume_panel"; + public static final String TILE_SCREEN_TIMEOUT = "screen_timeout"; + public static final String TILE_LIVE_DISPLAY = "live_display"; + public static final String TILE_USB_TETHER = "usb_tether"; + public static final String TILE_HEADS_UP = "heads_up"; + public static final String TILE_AMBIENT_DISPLAY = "ambient_display"; + public static final String TILE_SYNC = "sync"; + public static final String TILE_BATTERY_SAVER = "battery_saver"; + public static final String TILE_EDIT = "edit"; + public static final String TILE_DND = "dnd"; + + 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 STATIC_TILES_AVAILABLE = new ArrayList(); + protected static final ArrayList DYNAMIC_TILES_AVAILABLE = new ArrayList(); + protected static final ArrayList TILES_AVAILABLE = new ArrayList(); + + static { + 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_EDIT); + STATIC_TILES_AVAILABLE.add(TILE_CAST); + STATIC_TILES_AVAILABLE.add(TILE_HOTSPOT); + STATIC_TILES_AVAILABLE.add(TILE_INVERSION); + STATIC_TILES_AVAILABLE.add(TILE_DND); +// 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_VOLUME); +// 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); +// STATIC_TILES_AVAILABLE.add(TILE_BATTERY_SAVER); + +// 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); + } +} \ No newline at end of file diff --git a/src/java/org/cyanogenmod/internal/util/QSUtils.java b/src/java/org/cyanogenmod/internal/util/QSUtils.java new file mode 100644 index 0000000..c43f08e --- /dev/null +++ b/src/java/org/cyanogenmod/internal/util/QSUtils.java @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2015 The CyanogenMod 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 org.cyanogenmod.internal.util; + +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.net.Uri; +import android.os.Build; +import android.os.Handler; +import android.os.PowerManager; +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 cyanogenmod.power.PerformanceManager; +import cyanogenmod.providers.CMSettings; + +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 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 getAvailableTiles(Context context) { + filterTiles(context); + return QSConstants.TILES_AVAILABLE; + } + + public static List getDefaultTiles(Context context) { + final List tiles = new ArrayList<>(); + final String defaults = context.getString( + org.cyanogenmod.platform.internal.R.string.config_defaultQuickSettingsTiles); + if (!TextUtils.isEmpty(defaults)) { + final String[] array = TextUtils.split(defaults, Pattern.quote(",")); + for (String item : array) { + if (TextUtils.isEmpty(item)) { + continue; + } + tiles.add(item); + } + filterTiles(context, tiles); + } + return tiles; + } + + public static String getDefaultTilesAsString(Context context) { + List list = getDefaultTiles(context); + return TextUtils.join(",", list); + } + + private static void filterTiles(Context context, List tiles) { + boolean deviceSupportsMobile = deviceSupportsMobileData(context); + + // Tiles that need conditional filtering + Iterator iterator = tiles.iterator(); + while (iterator.hasNext()) { + String tileKey = iterator.next(); + boolean removeTile = false; + switch (tileKey) { + case QSConstants.TILE_CELLULAR: + case QSConstants.TILE_HOTSPOT: + case QSConstants.TILE_DATA: + case QSConstants.TILE_ROAMING: + case QSConstants.TILE_APN: + removeTile = !deviceSupportsMobile; + break; + case QSConstants.TILE_DDS: + removeTile = !deviceSupportsDdsSupported(context); + break; + case QSConstants.TILE_FLASHLIGHT: + removeTile = !deviceSupportsFlashLight(context); + break; + case QSConstants.TILE_BLUETOOTH: + removeTile = !deviceSupportsBluetooth(); + break; + case QSConstants.TILE_NFC: + removeTile = !deviceSupportsNfc(context); + break; + case QSConstants.TILE_COMPASS: + removeTile = !deviceSupportsCompass(context); + break; + case QSConstants.TILE_AMBIENT_DISPLAY: + removeTile = !deviceSupportsDoze(context); + break; + case QSConstants.TILE_PERFORMANCE: + removeTile = !deviceSupportsPowerProfiles(context); + break; + case QSConstants.TILE_BATTERY_SAVER: + removeTile = deviceSupportsPowerProfiles(context); + break; + + case QSConstants.DYNAMIC_TILE_SU: + removeTile = !supportsRootAccess(); + break; + } + if (removeTile) { + iterator.remove(); + } + } + } + + private static void filterTiles(Context context) { + if (!sAvailableTilesFiltered) { + filterTiles(context, QSConstants.TILES_AVAILABLE); + sAvailableTilesFiltered = true; + } + } + + 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 = CMSettings.Secure.getStringForUser(resolver, + CMSettings.Secure.QS_TILES, userId); + return !TextUtils.isEmpty(order) && 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( + CMSettings.Secure.getUriFor(CMSettings.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); + return (tm.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) + || tm.getLteOnGsmMode() != 0; + } + + public static boolean deviceSupportsDdsSupported(Context context) { + TelephonyManager tm = (TelephonyManager) + context.getSystemService(Context.TELEPHONY_SERVICE); + return tm.isMultiSimEnabled() + && tm.getMultiSimConfiguration() == TelephonyManager.MultiSimVariants.DSDA; + } + + public static boolean deviceSupportsMobileData(Context ctx) { + ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService( + Context.CONNECTIVITY_SERVICE); + return cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); + } + + public static boolean deviceSupportsBluetooth() { + return BluetoothAdapter.getDefaultAdapter() != null; + } + + public static boolean deviceSupportsNfc(Context context) { + PackageManager packageManager = context.getPackageManager(); + return packageManager.hasSystemFeature(PackageManager.FEATURE_NFC); + } + + public static boolean deviceSupportsFlashLight(Context context) { + CameraManager cameraManager = (CameraManager) context.getSystemService( + Context.CAMERA_SERVICE); + try { + String[] ids = cameraManager.getCameraIdList(); + for (String id : ids) { + CameraCharacteristics c = cameraManager.getCameraCharacteristics(id); + Boolean flashAvailable = c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE); + Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING); + if (flashAvailable != null + && flashAvailable + && lensFacing != null + && lensFacing == CameraCharacteristics.LENS_FACING_BACK) { + return true; + } + } + } catch (CameraAccessException | AssertionError e) { + // Ignore + } + return false; + } + + public static boolean deviceSupportsCompass(Context context) { + SensorManager sm = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + return sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null + && sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null; + } + + public static boolean deviceSupportsDoze(Context context) { + String name = context.getResources().getString( + com.android.internal.R.string.config_dozeComponent); + return !TextUtils.isEmpty(name); + } + + + public static boolean deviceSupportsPowerProfiles(Context context) { + PerformanceManager pm = PerformanceManager.getInstance(context); + return pm.getNumberOfProfiles() > 0; + } + + private static boolean supportsRootAccess() { + return Build.IS_DEBUGGABLE || "eng".equals(Build.TYPE); + } +} \ No newline at end of file