summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/util/cm/QSConstants.java1
-rw-r--r--core/java/com/android/internal/util/cm/QSUtils.java6
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_qs_camera.pngbin0 -> 3418 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_camera.pngbin0 -> 3214 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_qs_camera.pngbin0 -> 3575 bytes
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_camera.xml42
-rw-r--r--packages/SystemUI/res/values/cm_strings.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/quicksettings/CameraTile.java499
-rw-r--r--packages/SystemUI/src/com/android/systemui/quicksettings/QuickSettingsTile.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsController.java30
11 files changed, 578 insertions, 22 deletions
diff --git a/core/java/com/android/internal/util/cm/QSConstants.java b/core/java/com/android/internal/util/cm/QSConstants.java
index 0e49e39..044d5f9 100644
--- a/core/java/com/android/internal/util/cm/QSConstants.java
+++ b/core/java/com/android/internal/util/cm/QSConstants.java
@@ -29,6 +29,7 @@ public class QSConstants {
public static final String TILE_QUIETHOURS = "toggleQuietHours";
public static final String TILE_VOLUME = "toggleVolume";
public static final String TILE_EXPANDEDDESKTOP = "toggleExpandedDesktop";
+ public static final String TILE_CAMERA = "toggleCamera";
public static final String TILE_DELIMITER = "|";
public static ArrayList<String> TILES_DEFAULT = new ArrayList<String>();
diff --git a/core/java/com/android/internal/util/cm/QSUtils.java b/core/java/com/android/internal/util/cm/QSUtils.java
index 3da9a7c..39743a9 100644
--- a/core/java/com/android/internal/util/cm/QSUtils.java
+++ b/core/java/com/android/internal/util/cm/QSUtils.java
@@ -3,8 +3,8 @@ 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.res.Resources;
+import android.hardware.Camera;
import android.hardware.display.DisplayManager;
import android.hardware.display.WifiDisplayStatus;
import android.net.ConnectivityManager;
@@ -62,4 +62,8 @@ public class QSUtils {
Resources res = ctx.getResources();
return res.getBoolean(com.android.internal.R.bool.config_hasDockBattery);
}
+
+ public static boolean deviceSupportsCamera() {
+ return Camera.getNumberOfCameras() > 0;
+ }
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 80bb24d..57d31a1 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -45,6 +45,7 @@
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
<uses-permission android:name="android.permission.MASTER_CLEAR" />
<uses-permission android:name="android.permission.VIBRATE" />
+ <uses-permission android:name="android.permission.CAMERA" />
<!-- ActivityManager -->
<uses-permission android:name="android.permission.GET_TASKS" />
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_camera.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_camera.png
new file mode 100644
index 0000000..e0157f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_camera.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_camera.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_camera.png
new file mode 100644
index 0000000..17a2e9d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_camera.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_camera.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_camera.png
new file mode 100644
index 0000000..8a9b3a3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_camera.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_camera.xml b/packages/SystemUI/res/layout/quick_settings_tile_camera.xml
new file mode 100644
index 0000000..12cfebd
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_camera.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The CyanogenMod 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView android:id="@+id/camera_text"
+ style="@style/TextAppearance.QuickSettings.TileView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_centerInParent="true"
+ android:drawableTop="@drawable/ic_qs_camera"
+ android:text="@string/quick_settings_camera_label"
+ android:singleLine="true" />
+
+ <FrameLayout android:id="@+id/camera_surface_holder"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ImageView android:id="@+id/camera_surface_flash_overlay"
+ android:src="#88ffffff"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone" />
+
+ </FrameLayout>
+</RelativeLayout>
diff --git a/packages/SystemUI/res/values/cm_strings.xml b/packages/SystemUI/res/values/cm_strings.xml
index 5aff21f..d0a4362 100644
--- a/packages/SystemUI/res/values/cm_strings.xml
+++ b/packages/SystemUI/res/values/cm_strings.xml
@@ -65,11 +65,15 @@
<string name="quick_settings_lte">LTE</string>
<string name="quick_settings_lte_off">LTE off</string>
<string name="quick_settings_volume">Volume</string>
+ <string name="quick_settings_camera_label">Camera</string>
<!-- Expanded desktop strings break the rules a bit - the icon identifies the feature, the string indicates current state -->
<string name="quick_settings_expanded_desktop">Expanded</string>
<string name="quick_settings_expanded_desktop_off">Normal</string>
+ <!-- Camera tile toasts -->
+ <string name="quick_settings_camera_error_connect">Can\'t connect to camera</string>
+
<!-- Text to display next to the minimal graphical battery meter. [CHAR LIMIT=3] -->
<string name="status_bar_settings_battery_meter_min_format" translatable="false">
<xliff:g id="number">%d</xliff:g>
diff --git a/packages/SystemUI/src/com/android/systemui/quicksettings/CameraTile.java b/packages/SystemUI/src/com/android/systemui/quicksettings/CameraTile.java
new file mode 100644
index 0000000..02114b8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/quicksettings/CameraTile.java
@@ -0,0 +1,499 @@
+package com.android.systemui.quicksettings;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.hardware.Camera;
+import android.media.ExifInterface;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.Handler;
+import android.provider.MediaStore;
+import android.provider.MediaStore.Images;
+import android.provider.MediaStore.Images.ImageColumns;
+import android.provider.MediaStore.MediaColumns;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.OrientationEventListener;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewParent;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.PanelView;
+import com.android.systemui.statusbar.phone.QuickSettingsContainerView;
+import com.android.systemui.statusbar.phone.QuickSettingsController;
+
+public class CameraTile extends QuickSettingsTile {
+ private static final String DEFAULT_IMAGE_FILE_NAME_FORMAT = "'IMG'_yyyyMMdd_HHmmss";
+ private static final int CAMERA_ID = 0;
+
+ private Handler mHandler;
+ private TextView mTextView;
+ private FrameLayout mSurfaceLayout;
+ private SurfaceView mSurfaceView;
+ private View mFlashView;
+
+ private Camera mCamera;
+ private CameraOrientationListener mCameraOrientationListener = null;
+ private int mOrientation;
+ private int mJpegRotation;
+ private int mDisplayRotation;
+ private Camera.Size mCameraSize;
+ private boolean mCameraStarted;
+ private boolean mCameraBusy;
+
+ private Camera.CameraInfo mCameraInfo = new Camera.CameraInfo();
+ private Camera.Parameters mParams;
+
+ private Storage mStorage = new Storage();
+ private SimpleDateFormat mImageNameFormatter;
+
+ private Runnable mStartRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mCamera != null) {
+ return;
+ }
+
+ Camera.getCameraInfo(CAMERA_ID, mCameraInfo);
+
+ try {
+ mCamera = Camera.open(CAMERA_ID);
+ } catch (Exception e) {
+ Toast.makeText(mContext, R.string.quick_settings_camera_error_connect,
+ Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ // Orientation listener to rotate the camera preview
+ if (mCameraOrientationListener == null) {
+ mCameraOrientationListener = new CameraOrientationListener(mContext);
+ }
+ mCameraOrientationListener.enable();
+
+ mParams = mCamera.getParameters();
+
+ // Use smallest preview size that is bigger than the tile view
+ Camera.Size previewSize = mParams.getPreviewSize();
+ for (Camera.Size size : mParams.getSupportedPreviewSizes()) {
+ if ((size.width > mTile.getWidth() && size.height > mTile.getHeight()) &&
+ (size.width < previewSize.width && size.height < previewSize.height)) {
+ previewSize = size;
+ }
+ }
+ mParams.setPreviewSize(previewSize.width, previewSize.height);
+
+ // Use largest picture size
+ Camera.Size pictureSize = mParams.getPictureSize();
+ for (Camera.Size size : mParams.getSupportedPictureSizes()) {
+ if (size.width > pictureSize.width && size.height > pictureSize.height) {
+ pictureSize = size;
+ }
+ }
+ mCameraSize = pictureSize;
+ mParams.setPictureSize(pictureSize.width, pictureSize.height);
+
+ // Try focus with continuous modes first, then basic autofocus
+ List<String> focusModes = mParams.getSupportedFocusModes();
+ if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
+ mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
+ } else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
+ mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
+ } else if (mParams.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
+ mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
+ }
+
+ mCamera.setParameters(mParams);
+ updateOrientation();
+
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ final PanelView panel = getContainingPanel();
+ if (panel != null && panel.isFullyExpanded()) {
+ mHandler.postDelayed(this, 100);
+ } else {
+ mHandler.post(mReleaseCameraRunnable);
+ }
+ }
+ }, 100);
+
+ mTextView.setVisibility(View.GONE);
+ mSurfaceView = new CameraPreview(mContext, mCamera);
+ mSurfaceView.setVisibility(View.VISIBLE);
+ mSurfaceLayout.addView(mSurfaceView, 0);
+ }
+ };
+
+ private Runnable mTakePictureRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mCamera == null) {
+ return;
+ }
+
+ // Repeat until the preview has started and we can
+ // take picture
+ if (!mCameraStarted) {
+ mHandler.postDelayed(this, 200);
+ return;
+ }
+
+ // To avoid crashes don't post new picture requests
+ // if previous request has not returned
+ if (mCameraBusy) {
+ return;
+ }
+ mCameraBusy = true;
+
+ // Display flash animation above the preview
+ mFlashView.setVisibility(View.VISIBLE);
+ mFlashView.animate().alpha(0f).withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ mFlashView.setVisibility(View.GONE);
+ mFlashView.setAlpha(1f);
+ }
+ });
+
+ // Update the JPEG rotation\
+ if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
+ mJpegRotation = (mCameraInfo.orientation - mOrientation + 360) % 360;
+ } else {
+ mJpegRotation = (mCameraInfo.orientation + mOrientation) % 360;
+ }
+
+ mParams.setRotation(mJpegRotation);
+ mCamera.setParameters(mParams);
+
+ // Request a picture
+ try {
+ mCamera.takePicture(null, null, new Camera.PictureCallback() {
+ @Override
+ public void onPictureTaken(byte[] data, Camera camera) {
+ mCameraBusy = false;
+
+ long time = System.currentTimeMillis();
+
+ int orientation = (mOrientation + mDisplayRotation) % 360;
+
+ mStorage.addImage(mContext.getContentResolver(),
+ mImageNameFormatter.format(new Date(time)),
+ time, orientation, data, mCameraSize.width,
+ mCameraSize.height);
+
+ mCamera.startPreview();
+ }
+ });
+ } catch (RuntimeException e) {
+ // This can happen if user is pressing the
+ // tile too fast, nothing we can do
+ }
+ }
+ };
+
+ private Runnable mReleaseCameraRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mCamera == null) {
+ return;
+ }
+
+ mCamera.stopPreview();
+ mCamera.release();
+ mCamera = null;
+ mCameraStarted = false;
+ mCameraOrientationListener.disable();
+
+ mTextView.setVisibility(View.VISIBLE);
+ mSurfaceView.setVisibility(View.GONE);
+ mSurfaceLayout.removeView(mSurfaceView);
+ mSurfaceView = null;
+ }
+ };
+
+ private Runnable mAutoFocusRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mCameraStarted) {
+ mCamera.autoFocus(null);
+ }
+ }
+ };
+
+ public CameraTile(Context context, QuickSettingsController qsc, Handler handler) {
+ super(context, qsc, R.layout.quick_settings_tile_camera);
+ mHandler = handler;
+
+ String imageFileNameFormat = DEFAULT_IMAGE_FILE_NAME_FORMAT;
+ try {
+ final Resources camRes = context.getPackageManager()
+ .getResourcesForApplication("com.android.gallery3d");
+ int imageFileNameFormatResId = camRes.getIdentifier(
+ "image_file_name_format", "string", "com.android.gallery3d");
+ imageFileNameFormat = camRes.getString(imageFileNameFormatResId);
+ } catch (PackageManager.NameNotFoundException ex) {
+ // Use default
+ } catch (Resources.NotFoundException ex) {
+ // Use default
+ }
+ mImageNameFormatter = new SimpleDateFormat(imageFileNameFormat);
+
+ }
+
+ @Override
+ void onPostCreate() {
+ mOnLongClick = new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ if (mCamera != null) {
+ return false;
+ }
+
+ Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+ startSettingsActivity(intent);
+ return true;
+ }
+ };
+
+ mTextView = (TextView) mTile.findViewById(R.id.camera_text);
+ mSurfaceLayout = (FrameLayout) mTile.findViewById(R.id.camera_surface_holder);
+ mFlashView = mTile.findViewById(R.id.camera_surface_flash_overlay);
+
+ super.onPostCreate();
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (mCamera == null) {
+ mHandler.post(mStartRunnable);
+ } else {
+ mHandler.post(mTakePictureRunnable);
+ }
+ }
+
+ private PanelView getContainingPanel() {
+ ViewParent parent = mContainer;
+ while (parent != null) {
+ if (parent instanceof PanelView) {
+ return (PanelView) parent;
+ }
+ parent = parent.getParent();
+ }
+ return null;
+ }
+
+ private void updateOrientation() {
+ final WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ int rotation = wm.getDefaultDisplay().getRotation();
+
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ default:
+ mDisplayRotation = 0;
+ break;
+ case Surface.ROTATION_90:
+ mDisplayRotation = 90;
+ break;
+ case Surface.ROTATION_180:
+ mDisplayRotation = 180;
+ break;
+ case Surface.ROTATION_270:
+ mDisplayRotation = 270;
+ break;
+ }
+
+ int cameraOrientation;
+
+ if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
+ cameraOrientation = (mCameraInfo.orientation + mDisplayRotation) % 360;
+ cameraOrientation = (360 - cameraOrientation) % 360; // compensate the mirror
+ } else {
+ cameraOrientation = (mCameraInfo.orientation - mDisplayRotation + 360) % 360;
+ }
+
+ mCamera.setDisplayOrientation(cameraOrientation);
+ }
+
+ private class CameraOrientationListener extends OrientationEventListener {
+ public CameraOrientationListener(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onOrientationChanged(int orientation) {
+ if (mCamera == null || orientation == ORIENTATION_UNKNOWN) {
+ return;
+ }
+
+ mOrientation = (orientation + 45) / 90 * 90;
+ updateOrientation();
+ }
+ }
+
+ private class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
+ private SurfaceHolder mHolder;
+ private Camera mCamera;
+
+ public CameraPreview(Context context, Camera camera) {
+ super(context);
+ mCamera = camera;
+
+ // Install a SurfaceHolder.Callback so we get notified when the
+ // underlying surface is created and destroyed.
+ mHolder = getHolder();
+ mHolder.addCallback(this);
+ }
+
+ public void surfaceCreated(SurfaceHolder holder) {
+ // The Surface has been created, now tell the camera where
+ // to draw the preview.
+ try {
+ mCamera.setPreviewDisplay(holder);
+ mCamera.startPreview();
+ mCameraStarted = true;
+ mCameraBusy = false;
+ mHandler.postDelayed(mAutoFocusRunnable, 200);
+ } catch (IOException e) {
+ // Try release camera
+ mCamera.release();
+ }
+ }
+
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ }
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ }
+ }
+
+ private class Storage {
+ private static final String TAG = "CameraStorage";
+ private String mRoot = Environment.getExternalStorageDirectory().toString();
+ private Storage() {}
+
+ public String writeFile(String title, byte[] data) {
+ String path = generateFilepath(title);
+ FileOutputStream out = null;
+
+ try {
+ out = new FileOutputStream(path);
+ out.write(data);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to write data", e);
+ } finally {
+ try {
+ out.close();
+ } catch (Exception e) {
+ // Do nothing here
+ }
+ }
+ return path;
+ }
+
+ // Save the image and add it to media store.
+ public Uri addImage(ContentResolver resolver, String title, long date,
+ int orientation, byte[] jpeg, int width, int height) {
+ // Save the image.
+ String path = writeFile(title, jpeg);
+ return addImage(resolver, title, date, orientation, jpeg.length,
+ path, width, height);
+ }
+
+ // Add the image to media store.
+ public Uri addImage(ContentResolver resolver, String title, long date,
+ int orientation, int jpegLength, String path, int width, int height) {
+
+ try {
+ ExifInterface exif = new ExifInterface(path);
+ switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1)) {
+ case ExifInterface.ORIENTATION_ROTATE_90:
+ orientation = 90;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_180:
+ orientation = 180;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_270:
+ orientation = 270;
+ break;
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to read exif", e);
+ }
+
+ if ((mJpegRotation + orientation) % 180 != 0) {
+ int temp = width;
+ width = height;
+ height = width;
+ }
+
+ // Insert into MediaStore.
+ ContentValues values = new ContentValues(9);
+ values.put(ImageColumns.TITLE, title);
+ values.put(ImageColumns.DISPLAY_NAME, title + ".jpg");
+ values.put(ImageColumns.DATE_TAKEN, date);
+ values.put(ImageColumns.MIME_TYPE, "image/jpeg");
+
+ // Clockwise rotation in degrees. 0, 90, 180, or 270.
+ values.put(ImageColumns.ORIENTATION, orientation);
+ values.put(ImageColumns.DATA, path);
+ values.put(ImageColumns.SIZE, jpegLength);
+ values.put(MediaColumns.WIDTH, width);
+ values.put(MediaColumns.HEIGHT, height);
+
+ Uri uri = null;
+
+ try {
+ uri = resolver.insert(Images.Media.EXTERNAL_CONTENT_URI, values);
+ } catch (Throwable th) {
+ // This can happen when the external volume is already mounted, but
+ // MediaScanner has not notify MediaProvider to add that volume.
+ // The picture is still safe and MediaScanner will find it and
+ // insert it into MediaProvider. The only problem is that the user
+ // cannot click the thumbnail to review the picture.
+ Log.e(TAG, "Failed to write MediaStore" + th);
+ }
+ return uri;
+ }
+
+ private String generateDCIM() {
+ return new File(mRoot, Environment.DIRECTORY_DCIM).toString();
+ }
+
+ public String generateDirectory() {
+ return generateDCIM() + "/Camera";
+ }
+
+ private String generateFilepath(String title) {
+ return generateDirectory() + '/' + title + ".jpg";
+ }
+
+ public String generateBucketId() {
+ return String.valueOf(generateDirectory().toLowerCase().hashCode());
+ }
+
+ public int generateBucketIdInt() {
+ return generateDirectory().toLowerCase().hashCode();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/quicksettings/QuickSettingsTile.java b/packages/SystemUI/src/com/android/systemui/quicksettings/QuickSettingsTile.java
index 747e301..48828d0 100644
--- a/packages/SystemUI/src/com/android/systemui/quicksettings/QuickSettingsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/quicksettings/QuickSettingsTile.java
@@ -24,6 +24,7 @@ import com.android.systemui.statusbar.phone.QuickSettingsTileView;
public class QuickSettingsTile implements OnClickListener {
protected final Context mContext;
+ protected QuickSettingsContainerView mContainer;
protected QuickSettingsTileView mTile;
protected OnClickListener mOnClick;
protected OnLongClickListener mOnLongClick;
@@ -50,7 +51,8 @@ public class QuickSettingsTile implements OnClickListener {
public void setupQuickSettingsTile(LayoutInflater inflater, QuickSettingsContainerView container) {
mTile = (QuickSettingsTileView) inflater.inflate(R.layout.quick_settings_tile, container, false);
mTile.setContent(mTileLayout, inflater);
- container.addView(mTile);
+ mContainer = container;
+ mContainer.addView(mTile);
onPostCreate();
updateQuickSettings();
mTile.setOnClickListener(this);
@@ -73,8 +75,10 @@ public class QuickSettingsTile implements OnClickListener {
void updateQuickSettings(){
TextView tv = (TextView) mTile.findViewById(R.id.tile_textview);
- tv.setCompoundDrawablesWithIntrinsicBounds(0, mDrawable, 0, 0);
- tv.setText(mLabel);
+ if (tv != null) {
+ tv.setCompoundDrawablesWithIntrinsicBounds(0, mDrawable, 0, 0);
+ tv.setText(mLabel);
+ }
}
void startSettingsActivity(String action) {
@@ -99,8 +103,11 @@ public class QuickSettingsTile implements OnClickListener {
}
@Override
- public final void onClick(View v) {
- mOnClick.onClick(v);
+ public void onClick(View v) {
+ if (mOnClick != null) {
+ mOnClick.onClick(v);
+ }
+
ContentResolver resolver = mContext.getContentResolver();
boolean shouldCollapse = Settings.System.getIntForUser(resolver,
Settings.System.QS_COLLAPSE_PANEL, 0, UserHandle.USER_CURRENT) == 1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsController.java
index 6541424..568d73d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsController.java
@@ -22,6 +22,7 @@ import static com.android.internal.util.cm.QSConstants.TILE_AUTOROTATE;
import static com.android.internal.util.cm.QSConstants.TILE_BATTERY;
import static com.android.internal.util.cm.QSConstants.TILE_BLUETOOTH;
import static com.android.internal.util.cm.QSConstants.TILE_BRIGHTNESS;
+import static com.android.internal.util.cm.QSConstants.TILE_CAMERA;
import static com.android.internal.util.cm.QSConstants.TILE_DELIMITER;
import static com.android.internal.util.cm.QSConstants.TILE_EXPANDEDDESKTOP;
import static com.android.internal.util.cm.QSConstants.TILE_GPS;
@@ -43,14 +44,6 @@ import static com.android.internal.util.cm.QSConstants.TILE_VOLUME;
import static com.android.internal.util.cm.QSConstants.TILE_WIFI;
import static com.android.internal.util.cm.QSConstants.TILE_WIFIAP;
import static com.android.internal.util.cm.QSConstants.TILE_WIMAX;
-import static com.android.internal.util.cm.QSUtils.deviceSupportsBluetooth;
-import static com.android.internal.util.cm.QSUtils.deviceSupportsDockBattery;
-import static com.android.internal.util.cm.QSUtils.deviceSupportsImeSwitcher;
-import static com.android.internal.util.cm.QSUtils.deviceSupportsLte;
-import static com.android.internal.util.cm.QSUtils.deviceSupportsMobileData;
-import static com.android.internal.util.cm.QSUtils.deviceSupportsUsbTether;
-import static com.android.internal.util.cm.QSUtils.expandedDesktopEnabled;
-import static com.android.internal.util.cm.QSUtils.systemProfilesEnabled;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -67,6 +60,7 @@ import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
+import com.android.internal.util.cm.QSUtils;
import com.android.systemui.quicksettings.AirplaneModeTile;
import com.android.systemui.quicksettings.AlarmTile;
import com.android.systemui.quicksettings.AutoRotateTile;
@@ -74,6 +68,7 @@ import com.android.systemui.quicksettings.BatteryTile;
import com.android.systemui.quicksettings.BluetoothTile;
import com.android.systemui.quicksettings.BrightnessTile;
import com.android.systemui.quicksettings.BugReportTile;
+import com.android.systemui.quicksettings.CameraTile;
import com.android.systemui.quicksettings.DockBatteryTile;
import com.android.systemui.quicksettings.ExpandedDesktopTile;
import com.android.systemui.quicksettings.GPSTile;
@@ -153,9 +148,10 @@ public class QuickSettingsController {
mIMETile = null;
// Filter items not compatible with device
- boolean bluetoothSupported = deviceSupportsBluetooth();
- boolean mobileDataSupported = deviceSupportsMobileData(mContext);
- boolean lteSupported = deviceSupportsLte(mContext);
+ boolean cameraSupported = QSUtils.deviceSupportsCamera();
+ boolean bluetoothSupported = QSUtils.deviceSupportsBluetooth();
+ boolean mobileDataSupported = QSUtils.deviceSupportsMobileData(mContext);
+ boolean lteSupported = QSUtils.deviceSupportsLte(mContext);
if (!bluetoothSupported) {
TILES_DEFAULT.remove(TILE_BLUETOOTH);
@@ -201,6 +197,8 @@ public class QuickSettingsController {
qs = new BluetoothTile(mContext, this, mStatusBarService.mBluetoothController);
} else if (tile.equals(TILE_BRIGHTNESS)) {
qs = new BrightnessTile(mContext, this, mHandler);
+ } else if (tile.equals(TILE_CAMERA) && cameraSupported) {
+ qs = new CameraTile(mContext, this, mHandler);
} else if (tile.equals(TILE_RINGER)) {
qs = new RingerModeTile(mContext, this);
} else if (tile.equals(TILE_SYNC)) {
@@ -225,7 +223,7 @@ public class QuickSettingsController {
qs = new SleepScreenTile(mContext, this);
} else if (tile.equals(TILE_PROFILE)) {
mTileStatusUris.add(Settings.System.getUriFor(Settings.System.SYSTEM_PROFILES_ENABLED));
- if (systemProfilesEnabled(resolver)) {
+ if (QSUtils.systemProfilesEnabled(resolver)) {
qs = new ProfileTile(mContext, this);
}
} else if (tile.equals(TILE_NFC)) {
@@ -242,7 +240,7 @@ public class QuickSettingsController {
qs = new VolumeTile(mContext, this, mHandler);
} else if (tile.equals(TILE_EXPANDEDDESKTOP)) {
mTileStatusUris.add(Settings.System.getUriFor(Settings.System.EXPANDED_DESKTOP_STYLE));
- if (expandedDesktopEnabled(resolver)) {
+ if (QSUtils.expandedDesktopEnabled(resolver)) {
qs = new ExpandedDesktopTile(mContext, this, mHandler);
}
}
@@ -283,13 +281,13 @@ public class QuickSettingsController {
qs.setupQuickSettingsTile(inflater, mContainerView);
mQuickSettingsTiles.add(qs);
}
- if (deviceSupportsImeSwitcher(mContext) && Settings.System.getIntForUser(resolver,
+ if (QSUtils.deviceSupportsImeSwitcher(mContext) && Settings.System.getIntForUser(resolver,
Settings.System.QS_DYNAMIC_IME, 1, UserHandle.USER_CURRENT) == 1) {
mIMETile = new InputMethodTile(mContext, this);
mIMETile.setupQuickSettingsTile(inflater, mContainerView);
mQuickSettingsTiles.add(mIMETile);
}
- if (deviceSupportsUsbTether(mContext) && Settings.System.getIntForUser(resolver,
+ if (QSUtils.deviceSupportsUsbTether(mContext) && Settings.System.getIntForUser(resolver,
Settings.System.QS_DYNAMIC_USBTETHER, 1, UserHandle.USER_CURRENT) == 1) {
QuickSettingsTile qs = new UsbTetherTile(mContext, this);
qs.setupQuickSettingsTile(inflater, mContainerView);
@@ -298,7 +296,7 @@ public class QuickSettingsController {
}
private void loadDockBatteryTile(final ContentResolver resolver, final LayoutInflater inflater) {
- if (!deviceSupportsDockBattery(mContext)) {
+ if (!QSUtils.deviceSupportsDockBattery(mContext)) {
return;
}
if (Settings.System.getIntForUser(resolver,