/* * 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_AVAILBLE.contains(tileSpec); } @SuppressWarnings("unchecked") public static List getAvailableTiles(Context context) { filterTiles(context); return (List) QSConstants.TILES_AVAILABLE.clone(); } 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; } 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); } }