1. MainActivity.java
package com.jianli.virtualrecent;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
public class MainActivity extends Activity {
private static final String TAG = "VirtualRecent";
private static final String PREFERENCES_VIRTUAL_RECENT_SERVICE = "preferences_virtual_recent_service";
private static final String KEY_PREF_VIRTUAL_RECENT_SERVICE_STARTED = "key_pref_virtual_recent_service_started";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SecLog.e(TAG, "onCreate");
}
@Override
protected void onDestroy() {
SecLog.e(TAG, "onDestroy");
super.onDestroy();
}
@Override
protected void onPause() {
SecLog.e(TAG, "onPause");
super.onPause();
}
@Override
protected void onResume() {
SecLog.e(TAG, "onResume");
SharedPreferences mSharedPreferences = getSharedPreferences(PREFERENCES_VIRTUAL_RECENT_SERVICE, Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = mSharedPreferences.edit();
Intent intent = new Intent(this, VirtualRecentService.class);
if(mSharedPreferences.getBoolean(KEY_PREF_VIRTUAL_RECENT_SERVICE_STARTED, false) == false){
startService(intent);
editor.putBoolean(KEY_PREF_VIRTUAL_RECENT_SERVICE_STARTED, true);
}else{
stopService(intent);
editor.putBoolean(KEY_PREF_VIRTUAL_RECENT_SERVICE_STARTED, false);
}
editor.commit();
finish();
super.onResume();
}
}
2. VirtualRecentService.java
package com.jianli.virtualrecent;
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.os.IBinder;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.ImageButton;
import android.widget.LinearLayout;
@SuppressLint("InflateParams")
public class VirtualRecentService extends Service {
private static final String TAG = "VirtualRecentService";
private static final String PREFERENCES_VIRTUAL_RECENT_SERVICE = "preferences_virtual_recent_service";
private static final String KEY_PREFERENCES_VRS_WINDOW_X = "key_preferences_vrs_window_x";
private static final String KEY_PREFERENCES_VRS_WINDOW_Y = "key_preferences_vrs_window_y";
private static final String KEY_PREFERENCES_VRS_STATUSBAR_HEIGHT = "key_preferences_vrs_statusbar_height";
private static final String VRS_TOGGLE_RECENT_INTENT = "com.android.systemui.recent.action.TOGGLE_RECENTS";
private SharedPreferences mSharedPreferences;
private LinearLayout mFloatLayout;
private WindowManager.LayoutParams wmParams;
private WindowManager mWindowManager;
private ImageButton mBtnImage;
private static int mStatusBarHeight = 0;
private static float mPreviousX = 0;
private static float mPreviousY = 0;
private static boolean bIsMoved = false;
@Override
public IBinder onBind(Intent arg0) {
SecLog.e(TAG, "onBind");
return null;
}
@Override
public void onCreate() {
SecLog.e(TAG, "onCreate");
super.onCreate();
}
@Override
public void onDestroy() {
SecLog.e(TAG, "onDestroy");
if(mFloatLayout != null)
{
mWindowManager.removeView(mFloatLayout);
}
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
SecLog.e(TAG, "onStartCommand");
mSharedPreferences = getSharedPreferences(PREFERENCES_VIRTUAL_RECENT_SERVICE, Activity.MODE_PRIVATE);
LayoutInflater inflater = LayoutInflater.from(getApplication());
mFloatLayout = (LinearLayout) inflater.inflate(R.layout.float_layout, null);
mBtnImage = (ImageButton)mFloatLayout.findViewById(R.id.btn_recent);
mStatusBarHeight = mSharedPreferences.getInt(KEY_PREFERENCES_VRS_STATUSBAR_HEIGHT, 0);
if(0 == mStatusBarHeight){
mStatusBarHeight = getStatusBarHeight(getBaseContext());
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(KEY_PREFERENCES_VRS_STATUSBAR_HEIGHT, mStatusBarHeight);
editor.commit();
}
createFloatView();
bIsMoved = false;
return super.onStartCommand(intent, flags, startId);
}
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;
wmParams.x = mSharedPreferences.getInt(KEY_PREFERENCES_VRS_WINDOW_X, 0);
wmParams.y = mSharedPreferences.getInt(KEY_PREFERENCES_VRS_WINDOW_Y, 0);
mPreviousX = wmParams.x;
mPreviousY = wmParams.y;
wmParams.width = 77;
wmParams.height = 77;
mWindowManager.addView(mFloatLayout, wmParams);
mBtnImage.setOnTouchListener(new OnTouchListener(){
@Override
public boolean onTouch(View arg0, MotionEvent event) {
SecLog.e(TAG, "onTouch");
switch(event.getActionMasked()){
case MotionEvent.ACTION_DOWN:
SecLog.e(TAG, "onTouch, ACTION_DOWN");
mPreviousX = event.getRawX();
mPreviousY = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
SecLog.e(TAG, "onTouch, ACTION_MOVE");
if(Math.abs(mPreviousX - event.getRawX()) < 10 && Math.abs(mPreviousY - event.getRawY()) < 10)
return false;
bIsMoved = true;
wmParams.x = (int) (event.getRawX() - mFloatLayout.getMeasuredWidth()/2);
wmParams.y = (int) (event.getRawY() - mStatusBarHeight - mFloatLayout.getMeasuredHeight()/2);
mWindowManager.updateViewLayout(mFloatLayout, wmParams);
break;
case MotionEvent.ACTION_UP:
SecLog.e(TAG, "onTouch, ACTION_UP");
if(true == bIsMoved){
bIsMoved = false;
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(KEY_PREFERENCES_VRS_WINDOW_X, wmParams.x);
editor.putInt(KEY_PREFERENCES_VRS_WINDOW_Y, wmParams.y);
editor.commit();
return false;
}
Intent intent = new Intent(VRS_TOGGLE_RECENT_INTENT);
intent.setClassName("com.android.systemui", "com.android.systemui.recent.RecentsActivity");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(intent);
break;
default:
SecLog.e(TAG, "onTouch,event="+event.getActionMasked());
break;
}
return false;
}
});
}
@Override
public boolean onUnbind(Intent intent) {
SecLog.e(TAG, "onUnbind");
return super.onUnbind(intent);
}
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;
}
}
3. VirtualRecentBootReceiver.java
package com.jianli.virtualrecent;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.widget.Toast;
public class VirtualRecentBootReceiver extends BroadcastReceiver {
private static final String TAG = "VirtualRecentBootReceiver";
private static final String PREFERENCES_VIRTUAL_RECENT_SERVICE = "preferences_virtual_recent_service";
private static final String KEY_PREF_VIRTUAL_RECENT_SERVICE_STARTED = "key_pref_virtual_recent_service_started";
@Override
public void onReceive(Context context, Intent arg1) {
SecLog.e(TAG, "onReceive");
Toast.makeText(context, "Boot complete", Toast.LENGTH_LONG).show();
Intent intent = new Intent(context, VirtualRecentService.class);
context.startService(intent);
SharedPreferences mSharedPreferences = context.getSharedPreferences(PREFERENCES_VIRTUAL_RECENT_SERVICE, Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putBoolean(KEY_PREF_VIRTUAL_RECENT_SERVICE_STARTED, true);
editor.commit();
}
}
4. Manifest.java
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jianli.virtualrecent"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="14" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".MainActivity"
android:theme="@android:style/Theme.NoDisplay"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".VirtualRecentService">
</service>
<receiver android:name="VirtualRecentBootReceiver">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED">
</action>
</intent-filter>
</receiver>
</application>
</manifest>
5. activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${relativePackage}.${activityClass}" >
</RelativeLayout>
6. 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" >
<ImageButton
android:id="@+id/btn_recent"
android:src="@drawable/recent_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>