1. MainActivity.java
package com.jean.lee.floatcamera;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.widget.Toast;
import com.jean.lee.floatcamera.service.FloatCameraService;
import com.jean.lee.floatcamera.util.SecLog;
@SuppressLint("NewApi")
public class MainActivity extends Activity {
private static final String TAG = "FloatCamera";
private static final String FLOAT_CAM_SERVICE_PREFERENCES = "pref_float_camera_service";
private static final String KEY_PREFERENCES_SERVICE_STARTED = "key_preferences_service_started";
private static final String KEY_PREFERENCES_SCREEN_HEIGHT = "key_preferences_screen_height";
private static final String KEY_PREFERENCES_CAMERA_NUMBERS = "key_preferences_camera_numbers";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SecLog.e(TAG, "onCreate");
}
@Override
protected void onResume() {
SecLog.e(TAG, "onResume");
SharedPreferences mSharedPreferences = getSharedPreferences(FLOAT_CAM_SERVICE_PREFERENCES, Activity.MODE_PRIVATE);
if(mSharedPreferences.getInt(KEY_PREFERENCES_CAMERA_NUMBERS, -2) == 0){
Toast.makeText(this, R.string.toast_no_camera, Toast.LENGTH_SHORT).show();
finish();
}else if(mSharedPreferences.getInt(KEY_PREFERENCES_CAMERA_NUMBERS, -2) == -2){
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(KEY_PREFERENCES_CAMERA_NUMBERS, Camera.getNumberOfCameras());
editor.commit();
}
if(mSharedPreferences.getInt(KEY_PREFERENCES_SCREEN_HEIGHT, 0) == 0){
DisplayMetrics dm = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getMetrics(dm);
int screenHeight = dm.heightPixels;
SecLog.e(TAG, "screenHeight="+screenHeight);
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(KEY_PREFERENCES_SCREEN_HEIGHT, screenHeight);
editor.commit();
}
Intent intent = new Intent(MainActivity.this, FloatCameraService.class);
SharedPreferences.Editor editor = mSharedPreferences.edit();
if(!mSharedPreferences.getBoolean(KEY_PREFERENCES_SERVICE_STARTED, false)){
SecLog.e(TAG, "call start service");
startService(intent);
editor.putBoolean(KEY_PREFERENCES_SERVICE_STARTED, true);
}else {
SecLog.e(TAG, "call stop service");
stopService(intent);
editor.putBoolean(KEY_PREFERENCES_SERVICE_STARTED, false);
}
editor.commit();
finish();
super.onResume();
}
@Override
protected void onDestroy() {
SecLog.e(TAG, "onDestroy");
super.onDestroy();
}
@Override
protected void onPause() {
SecLog.e(TAG, "onPause");
super.onPause();
}
}
2. FloatCameraService.java
package com.jean.lee.floatcamera.service;
import java.io.IOException;
import java.lang.reflect.Field;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.os.IBinder;
import android.os.Vibrator;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.jean.lee.floatcamera.R;
import com.jean.lee.floatcamera.util.SecLog;
@SuppressLint("NewApi")
public class FloatCameraService extends Service implements SurfaceHolder.Callback{
private static final String TAG = "FloatCameraService";
private static final String FLOAT_CAM_SERVICE_PREFERENCES = "pref_float_camera_service";
private static final String KEY_PREFERENCES_CAMERA_ID = "key_preferences_camera_id";
private static final String KEY_PREFERENCES_WINDOW_X = "key_preferences_window_x";
private static final String KEY_PREFERENCES_WINDOW_Y = "key_preferences_window_y";
private static final String KEY_PREFERENCES_WINDOW_WIDTH_BACK = "key_preferences_window_width_back";
private static final String KEY_PREFERENCES_WINDOW_HEIGHT_BACK = "key_preferences_window_height_back";
private static final String KEY_PREFERENCES_WINDOW_WIDTH_FRONT = "key_preferences_window_width_front";
private static final String KEY_PREFERENCES_WINDOW_HEIGHT_FRONT = "key_preferences_window_height_front";
private static final String KEY_PREFERENCES_STATUSBAR_HEIGHT = "key_preferences_statusbar_height";
private static final String KEY_PREFERENCES_SCREEN_HEIGHT = "key_preferences_screen_height";
private static final String KEY_PREFERENCES_CAMERA_NUMBERS = "key_preferences_camera_numbers";
LinearLayout mFloatLayout;
WindowManager.LayoutParams wmParams;
WindowManager mWindowManager;
private SurfaceView mSvPreview;
private SurfaceHolder mSurfaceHolder;
private Camera mCamera;
private Parameters mParameters;
private static final int DEFAULT_CAMERA_ID = CameraInfo.CAMERA_FACING_BACK;
private static int mCameraId = DEFAULT_CAMERA_ID;
private static int mCameraNumbers;
private SharedPreferences mSharedPreferences;
private boolean bLongPressed = false;
private boolean bMultiTouchPressed = false;
private static int mStatusBarHeight = 0;
private static int mWindowWidth = 270;
private static int mWindowHeight = 480;
private static final int PREVIEW_4_3_WIDTH = 300;
private static final int PREVIEW_4_3_HEIGHT = 400;
private static final int PREVIEW_16_9_WIDTH = 270;
private static final int PREVIEW_16_9_HEIGHT = 480;
@Override
public void onCreate() {
SecLog.e(TAG, "onCreate");
super.onCreate();
}
@Override
public void onDestroy() {
SecLog.e(TAG, "onDestroy");
if(mFloatLayout != null)
{
mWindowManager.removeView(mFloatLayout);
}
if(null != mCamera){
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
SecLog.e(TAG, "onStartCommand");
mSharedPreferences = getSharedPreferences(FLOAT_CAM_SERVICE_PREFERENCES, Activity.MODE_PRIVATE);
LayoutInflater inflater = LayoutInflater.from(getApplication());
mFloatLayout = (LinearLayout) inflater.inflate(R.layout.float_layout, null);
mSvPreview = (SurfaceView)mFloatLayout.findViewById(R.id.sv_preview);
mSurfaceHolder = mSvPreview.getHolder();
mSurfaceHolder.addCallback(this);
mStatusBarHeight = mSharedPreferences.getInt(KEY_PREFERENCES_STATUSBAR_HEIGHT, 0);
if(0 == mStatusBarHeight){
mStatusBarHeight = getStatusBarHeight(getBaseContext());
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(KEY_PREFERENCES_STATUSBAR_HEIGHT, mStatusBarHeight);
editor.commit();
}
openCamera();
createFloatView();
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
SecLog.e(TAG, "onUnbind");
return super.onUnbind(intent);
}
@Override
public IBinder onBind(Intent arg0) {
SecLog.e(TAG, "onBind");
return null;
}
@SuppressLint("InflateParams")
private void createFloatView()
{
SecLog.e(TAG, "createFloatView");
wmParams = new WindowManager.LayoutParams();
mWindowManager = (WindowManager)getApplication().getSystemService(getApplication().WINDOW_SERVICE);
wmParams.type = LayoutParams.TYPE_PHONE;
//设置图片格式,效果为背景透明
wmParams.format = PixelFormat.RGBA_8888;
//设置浮动窗口不可聚焦(实现操作除浮动窗口外的其他可见窗口的操作)
wmParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE;
//调整悬浮窗显示的停靠位置为左侧置顶
wmParams.gravity = Gravity.LEFT | Gravity.TOP;
// 以屏幕左上角为原点,设置x、y初始值,相对于gravity
wmParams.x = mSharedPreferences.getInt(KEY_PREFERENCES_WINDOW_X, 0);
wmParams.y = mSharedPreferences.getInt(KEY_PREFERENCES_WINDOW_Y, 0);
/* //设置悬浮窗口长宽数据
wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;*/
setOptimizeWindowSize();
// 设置悬浮窗口长宽数据
wmParams.width = mWindowWidth;
wmParams.height = mWindowHeight;
mWindowManager.addView(mFloatLayout, wmParams);
mFloatLayout.measure(View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED), View.MeasureSpec
.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
mFloatLayout.setOnTouchListener(new OnTouchListener(){
@Override
public boolean onTouch(View arg0, MotionEvent event) {
switch(event.getActionMasked()){
case MotionEvent.ACTION_DOWN:
SecLog.e(TAG, "onTouch, ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
SecLog.e(TAG, "onTouch, ACTION_MOVE");
if(bLongPressed){
//getRawX是触摸位置相对于屏幕的坐标,getX是相对于按钮的坐标
wmParams.x = (int) event.getRawX() - mSvPreview.getMeasuredWidth()/2;
//减25为状态栏的高度
wmParams.y = (int) event.getRawY() - mSvPreview.getMeasuredHeight()/2 - mStatusBarHeight;
mWindowManager.updateViewLayout(mFloatLayout, wmParams);
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
SecLog.e(TAG, "onTouch, ACTION_POINTER_DOWN");
break;
case MotionEvent.ACTION_POINTER_UP:
SecLog.e(TAG, "onTouch, ACTION_POINTER_UP");
break;
case MotionEvent.ACTION_UP:
SecLog.e(TAG, "onTouch, ACTION_UP");
if(bLongPressed){
bLongPressed = false;
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(KEY_PREFERENCES_WINDOW_X, wmParams.x);
editor.putInt(KEY_PREFERENCES_WINDOW_Y, wmParams.y);
editor.commit();
}else{
if(mSharedPreferences.getInt(KEY_PREFERENCES_CAMERA_NUMBERS, -2) == 1){
Toast.makeText(getBaseContext(), R.string.toast_only_one_camera, Toast.LENGTH_SHORT).show();
return false;
}
switchCamera();
startPreview();
}
break;
default:
SecLog.e(TAG, "onTouch,event="+event.getActionMasked());
break;
}
return false;
}
});
mFloatLayout.setOnLongClickListener(new OnLongClickListener(){
@Override
public boolean onLongClick(View arg0) {
SecLog.e(TAG, "onLongClick");
bLongPressed = true;
Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(100);
return false;
}
});
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
SecLog.e(TAG, "surfaceChanged");
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
SecLog.e(TAG, "surfaceCreated");
startPreview();
}
private void openCamera(){
SecLog.e(TAG, "openCamera");
if(null == mCamera && null != mSharedPreferences){
mCameraId = mSharedPreferences.getInt(KEY_PREFERENCES_CAMERA_ID, DEFAULT_CAMERA_ID);
mCamera = Camera.open(mCameraId);
mParameters = mCamera.getParameters();
}
}
private void switchCamera(){
SecLog.e(TAG, "switchCamera");
if(null != mCamera){
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
SharedPreferences.Editor editor = mSharedPreferences.edit();
mCameraId = mSharedPreferences.getInt(KEY_PREFERENCES_CAMERA_ID, DEFAULT_CAMERA_ID);
if(CameraInfo.CAMERA_FACING_BACK == mCameraId){
mCameraId = CameraInfo.CAMERA_FACING_FRONT;
mCamera = Camera.open(mCameraId);
}else{
mCameraId = CameraInfo.CAMERA_FACING_BACK;
mCamera = Camera.open(mCameraId);
}
editor.putInt(KEY_PREFERENCES_CAMERA_ID, mCameraId);
editor.commit();
if(mCamera != null){
mParameters = mCamera.getParameters();
}
}
private void startPreview(){
SecLog.e(TAG, "startPreview");
if(null != mCamera){
try {
mCamera.setPreviewDisplay(mSurfaceHolder);
} catch (IOException e) {
e.printStackTrace();
}
if(null != mParameters){
SecLog.e(TAG, "preview size:"+mParameters.getPreviewSize().width+"x"+mParameters.getPreviewSize().height);
}
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
updateWindownSize();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
SecLog.e(TAG, "surfaceDestroyed");
}
public static int getStatusBarHeight(Context context){
SecLog.e(TAG, "getStatusBarHeight");
Class<?> c = null;
Object obj = null;
Field field = null;
int x = 0, statusBarHeight = 0;
try {
c = Class.forName("com.android.internal.R$dimen");
obj = c.newInstance();
field = c.getField("status_bar_height");
x = Integer.parseInt(field.get(obj).toString());
statusBarHeight = context.getResources().getDimensionPixelSize(x);
} catch (Exception e1) {
e1.printStackTrace();
}
return statusBarHeight;
}
public void setOptimizeWindowSize(){
SecLog.e(TAG, "setOptimizeWindowSize");
if(mCameraId == CameraInfo.CAMERA_FACING_BACK) {
mWindowWidth = mSharedPreferences.getInt(KEY_PREFERENCES_WINDOW_WIDTH_BACK, 0);
mWindowHeight = mSharedPreferences.getInt(KEY_PREFERENCES_WINDOW_HEIGHT_BACK, 0);
}else{
mWindowWidth = mSharedPreferences.getInt(KEY_PREFERENCES_WINDOW_WIDTH_FRONT, 0);
mWindowHeight = mSharedPreferences.getInt(KEY_PREFERENCES_WINDOW_HEIGHT_FRONT, 0);
}
if(0 == mWindowWidth || 0 == mWindowHeight) {
int screenHeight = mSharedPreferences.getInt(KEY_PREFERENCES_SCREEN_HEIGHT, 0);
float ratio = (float)mParameters.getPreviewSize().width/(float)mParameters.getPreviewSize().height;
if(Math.abs(ratio-16.0/9.0) < 1.0E-6) {// 16/9
mWindowWidth = PREVIEW_16_9_WIDTH;
mWindowHeight = PREVIEW_16_9_HEIGHT;
if(screenHeight < 1000){
mWindowWidth = mWindowWidth*5/6;
mWindowHeight = mWindowHeight*5/6;
}
}else if(Math.abs(ratio-4.0/3.0) < 1.0E-6){
mWindowWidth = PREVIEW_4_3_WIDTH;
mWindowHeight = PREVIEW_4_3_HEIGHT;
if(screenHeight < 1000){
mWindowWidth = mWindowWidth*4/5;
mWindowHeight = mWindowHeight*4/5;
}
}else{
mWindowWidth = PREVIEW_4_3_WIDTH;
mWindowHeight = PREVIEW_4_3_HEIGHT;
}
SecLog.e(TAG, "width height:"+mWindowWidth+","+mWindowHeight);
SharedPreferences.Editor editor = mSharedPreferences.edit();
if(mCameraId == CameraInfo.CAMERA_FACING_BACK) {
editor.putInt(KEY_PREFERENCES_WINDOW_WIDTH_BACK, mWindowWidth);
editor.putInt(KEY_PREFERENCES_WINDOW_HEIGHT_BACK, mWindowHeight);
}else{
editor.putInt(KEY_PREFERENCES_WINDOW_WIDTH_FRONT, mWindowWidth);
editor.putInt(KEY_PREFERENCES_WINDOW_HEIGHT_FRONT, mWindowHeight);
}
editor.commit();
}
}
public void updateWindownSize(){
SecLog.e(TAG, "updateWindownSize");
setOptimizeWindowSize();
wmParams.width = mWindowWidth;
wmParams.height = mWindowHeight;
mWindowManager.updateViewLayout(mFloatLayout, wmParams);
}
}
3. Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jean.lee.floatcamera"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="14" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoDisplay" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".service.FloatCameraService"></service>
</application>
</manifest>
4. float_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<SurfaceView
android:id="@+id/sv_preview"
android:visibility="visible"
android:text="TestTest"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>