Android AIDL 實現兩個APP之間的跨進程通信實例
1 Service端創建
首先需要創建一個Android工程然後創建AIDL文件,創建AIDL文件主要爲了生成繼承了Binder的Stub類,以便應用Binder進行進程間通信
servier端結構如下
AIDL代碼如下
- // IBookManager.aidl
- package com.example.bookserver.aidl;
-
- // Declare any non-default types here with import statements
- import com.example.bookserver.aidl.Book;
- interface IBookManager {
- /**
- * Demonstrates some basic types that you can use as parameters
- * and return values in AIDL.
- */
- void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
- double aDouble, String aString);
-
- List<Book> getBook();
- boolean addBook(in Book book);
-
- }
之後創建一個實現了Parcelable的Book.java類用來傳遞數據
- package com.example.bookserver.aidl;
-
- import android.os.Parcel;
- import android.os.Parcelable;
-
- /**
- * Created by SAMSUNG on 2016-09-07.
- */
- public class Book implements Parcelable {
- private int id;
- private String name ;
-
- public int getId() {
- return id;
- }
-
- public void setId(int id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- @Override
- public String toString() {
- return "Book{" +
- "id=" + id +
- ", name='" + name + '\'' +
- '}';
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(this.id);
- dest.writeString(this.name);
- }
-
- public Book() {
- }
-
- protected Book(Parcel in) {
- this.id = in.readInt();
- this.name = in.readString();
- }
-
- public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {
- @Override
- public Book createFromParcel(Parcel source) {
- return new Book(source);
- }
-
- @Override
- public Book[] newArray(int size) {
- return new Book[size];
- }
- };
- }
最後我們來寫一個Service用於客戶端綁定
- package com.example.bookserver.service;
-
- import android.app.Service;
- import android.content.Intent;
- import android.os.Binder;
- import android.os.IBinder;
- import android.os.RemoteException;
-
- import com.example.bookserver.aidl.Book;
- import com.example.bookserver.aidl.IBookManager;
-
- import java.util.List;
- import java.util.concurrent.CopyOnWriteArrayList;
-
-
- public class BookService extends Service {
- private CopyOnWriteArrayList<Book> boookList = new CopyOnWriteArrayList<Book>();
- public BookService() {
-
- }
- Binder binder = new IBookManager.Stub(){
-
- @Override
- public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
-
- }
-
- @Override
- public List<Book> getBook() throws RemoteException {
- return boookList;
- }
-
- @Override
- public boolean addBook(Book book) throws RemoteException {
- return boookList.add(book);
- }
- };
- @Override
- public IBinder onBind(Intent intent) {
- return binder;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- Book book = new Book();
- book.setId(12345);
- book.setName("Book 1");
- boookList.add(book);
- }
- }
這樣Server端就搞定了,接下來就該進行Client端的代碼編寫了
2 Client端
Client端結構如下
首先我們要講AndroidStudio 通過AIDL生成的Binder導入到Client中並將Book.java也導入到Client中
然後寫進行Service的綁定
- package com.example.bookclient;
-
- import android.app.Service;
- import android.content.ComponentName;
- import android.content.Context;
- import android.content.Intent;
- import android.content.ServiceConnection;
- import android.content.pm.PackageManager;
- import android.content.pm.ResolveInfo;
- import android.os.IBinder;
- import android.util.Log;
-
- import com.example.bookserver.aidl.IBookManager;
-
- import java.util.List;
-
- /**
- * Created by SAMSUNG on 2016-09-07.
- */
- public class BookServiceManager {
- Context mContext = null;
- IBookManager mService = null;
- private static BookServiceManager bsm ;
- public static BookServiceManager getInstance(Context context){
- if(bsm==null){
- bsm = new BookServiceManager(context);
- }
- return bsm;
- }
- public IBookManager getBookServie(){
- if(mService==null){
- Log.d("BookServiceManager", "getBookServie: ");
- this.connectService();
-
- }
- return mService;
- }
-
- public BookServiceManager(Context mContext) {
- this.mContext = mContext;
- }
-
- ServiceConnection scc = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- Log.d("BookServiceManager", "getBookServie: 2 ==> Bind ");
- mService = IBookManager.Stub.asInterface(service);
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mService = null;
- }
- };
- public boolean connectService(){
- if(mService == null){
- Log.d("BookServiceManager", "getBookServie: 2");
- Intent intent = new Intent("com.example.bookserver.service.BookService");
- final Intent eintent = new Intent(createExplicitFromImplicitIntent(mContext,intent));
- mContext.bindService(eintent,scc, Service.BIND_AUTO_CREATE);
- }
- return true;
- }
-
- public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
- // Retrieve all services that can match the given intent
- PackageManager pm = context.getPackageManager();
- List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
-
- // Make sure only one match was found
- if (resolveInfo == null || resolveInfo.size() != 1) {
- return null;
- }
-
- // Get component info and create ComponentName
- ResolveInfo serviceInfo = resolveInfo.get(0);
- String packageName = serviceInfo.serviceInfo.packageName;
- String className = serviceInfo.serviceInfo.name;
- ComponentName component = new ComponentName(packageName, className);
-
- // Create a new intent. Use the old one for extras and such reuse
- Intent explicitIntent = new Intent(implicitIntent);
-
- // Set the component to be explicit
- explicitIntent.setComponent(component);
-
- return explicitIntent;
- }
- }
最後對設置Button進行調用
- package com.example.bookclient;
-
- import android.os.Bundle;
- import android.os.RemoteException;
- import android.support.v7.app.AppCompatActivity;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
-
- import com.example.bookserver.aidl.Book;
- import com.example.bookserver.aidl.IBookManager;
-
- public class MainActivity extends AppCompatActivity {
- IBookManager mBookService ;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- Button button = (Button) findViewById(R.id.button);
- Button addButton = (Button) findViewById(R.id.button3);
- Button findButton = (Button) findViewById(R.id.button2);
- BookServiceManager.getInstance(getApplication()).connectService();
- button.setOnClickListener(new View.OnClickListener(){
-
- @Override
- public void onClick(View v) {
-
- mBookService = BookServiceManager.getInstance(getApplication()).getBookServie();
-
- }
- });
-
- addButton.setOnClickListener(new View.OnClickListener(){
-
- @Override
- public void onClick(View v) {
- Book book = new Book();
- book.setId(2345);
- book.setName("add book!!");
- try {
- mBookService.addBook(book);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
-
- }
- });
-
- findButton.setOnClickListener(new View.OnClickListener(){
-
- @Override
- public void onClick(View v) {
-
- try {
- Log.d("MainActivity", mBookService.getBook().toString());
- } catch (RemoteException e) {
- e.printStackTrace();
- }
-
- }
- });
- }
- }
1)截屏接口、2)靜默安裝接口、3)按鍵控制接口、4)關機/重啓控制接口、5)關閉應用接口、
6)未知來源開關接口、7)控制應用使用接口、8)控制推送通知接口、9)控制SD/TF卡接口、10)控制USB口接口、
11) 網址/IP白名單接口、12)APK安裝白名單接口、13)應用卸載接口、14)護眼模式開關接口、15)應用聯網控制接口、
16)啓動Service或Activity接口、17)控制無障礙服務接口、18)控制設備管理器接口、19)控制訪問使用記錄接口、
20)聯繫人白名單接口、21)獲取聯繫人白名單接口
- package com.prize.txInterface.util;
-
- import com.prize.txInterface.application.TXApplication;
-
- import android.util.Log;
-
- public class TXLog {
-
- public static int d(String tag, String msg) {
- if (TXApplication.DEBUG) {
- return Log.d(tag, msg+getFunctionName());
- } else {
- return 0;
- }
- }
- public static int i(String tag, String msg) {
- if (TXApplication.DEBUG) {
- return Log.d(tag, msg+getFunctionName());
- } else {
- return 0;
- }
- }
-
- public static int e(String tag, String msg) {
- if (TXApplication.DEBUG) {
- return Log.e(tag, msg+getFunctionName());
- } else {
- return 0;
- }
- }
- /**
- * 方便日誌定位
- * add by mafei
- * @param tag 標籤
- * @return
- */
- private static String getFunctionName()
- {
- StackTraceElement[] sts = Thread.currentThread().getStackTrace();
- if(sts == null)
- {
- return null;
- }
- for(StackTraceElement st : sts)
- {
- if(st.isNativeMethod())
- {
- continue;
- }
- if(st.getClassName().equals(Thread.class.getName()))
- {
- continue;
- }
- if(st.getClassName().equals(TXLog.class.getName()))
- {
- continue;
- }
- return "[" + Thread.currentThread().getName() + ": "
- + st.getFileName() + ":" + st.getLineNumber() + " "
- + st.getMethodName() + " ]";
- }
- return null;
- }
-
- }
- package com.prize.txInterface.provider;
-
- import com.prize.txInterface.util.TXLog;
-
- import android.content.ContentProvider;
- import android.content.ContentResolver;
- import android.content.ContentValues;
- import android.content.Context;
- import android.content.UriMatcher;
- import android.database.Cursor;
- import android.database.sqlite.SQLiteDatabase;
- import android.database.sqlite.SQLiteOpenHelper;
- import android.net.Uri;
-
- public class PrizeWhiteListProvider extends ContentProvider{
-
- public static final String TAG = "snail_PrizeWhiteListProvider";
- public static final String DB_NAME = "whitelist.db";
- public static final int DB_VESION = 1;
- public static Uri CONTENT_URI_INSTALL = null;
- public static Uri CONTENT_URI_IP = null;
- public static Uri CONTENT_URI_CONTACT = null;
- private static UriMatcher sUriMatcher;
-
-
- public static final String TABLE_NAME_INSTALL = "install";
- public static final String TABLE_NAME_IP = "ip";
- public static final String TABLE_NAME_CONTACT = "contact";
- private static final int _INSTALL = 1;
- private static final int _IP = 2;
- private static final int _CONTACT = 3;
-
- private ContentResolver mContentResolver;
- static DatabaseHelper mOpenHelper;
-
- static SQLiteDatabase db;
-
- public static SQLiteDatabase getDbInstance(Context context){
- TXLog.i(TAG, "--whitelist.db-----onCreate----getDbInstance---- ");
- if(db==null)
- {
- mOpenHelper = new DatabaseHelper(context);
- db = mOpenHelper.getReadableDatabase();
- }
- return db;
- }
- @Override
- public boolean onCreate() {
- // TODO Auto-generated method stub
- TXLog.i(TAG, "--whitelist.db-----onCreate-- ");
- String db_auth = getContext().getPackageName() + ".provider";
- CONTENT_URI_INSTALL = Uri.parse("content://" + db_auth + "/"+ TABLE_NAME_INSTALL);
- CONTENT_URI_IP = Uri.parse("content://" + db_auth + "/"+ TABLE_NAME_IP);
- CONTENT_URI_CONTACT = Uri.parse("content://" + db_auth + "/"+ TABLE_NAME_CONTACT);
- sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- sUriMatcher.addURI(db_auth, TABLE_NAME_INSTALL, _INSTALL);
- sUriMatcher.addURI(db_auth, TABLE_NAME_IP, _IP);
- sUriMatcher.addURI(db_auth, TABLE_NAME_CONTACT, _CONTACT);
- getDbInstance(this.getContext());
- mContentResolver = getContext().getContentResolver();
- return true;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {
- // TODO Auto-generated method stub
- Cursor cur = null;
- String tableName = getTableName(uri);
- TXLog.i(TAG, "--whitelist.db-----query tableName = " + tableName+ " selection = " + selection);
- cur = db.query(tableName, projection, selection, selectionArgs, null,null, sortOrder);
- return cur;
- }
-
- @Override
- public String getType(Uri uri) {
- // TODO Auto-generated method stub
- throw new IllegalArgumentException("Uri IllegalArgument:" + uri);
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- // TODO Auto-generated method stub
- long id = -1;
- String tableName = getTableName(uri);
- TXLog.i(TAG, "--whitelist.db-----insert tableName = " + tableName);
- id = db.insert(tableName, "Content is empty", values);
- if (id == -1) {
- return null;
- }
- return Uri.parse("" + id);
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- // TODO Auto-generated method stub
- int num = 0;
- String tableName = getTableName(uri);
- TXLog.i(TAG, "--whitelist.db-----delete tableName = " + tableName+ "selection = " + selection);
- num = db.delete(tableName, selection, selectionArgs);
- return num;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection,
- String[] selectionArgs) {
- // TODO Auto-generated method stub
- int num = 0;
- String tableName = getTableName(uri);
- TXLog.i(TAG, "--whitelist.db-----update tableName = " + tableName+ "selection = " + selection);
- num = db.update(tableName, values, selection, selectionArgs);
- return num;
- }
-
- public String getTableName(Uri uri) {
- switch (sUriMatcher.match(uri)) {
- case _INSTALL://
- return TABLE_NAME_INSTALL;
- case _IP://
- return TABLE_NAME_IP;
- case _CONTACT://
- return TABLE_NAME_CONTACT;
- default:
- return null;
- }
- }
- public static class DatabaseHelper extends SQLiteOpenHelper {
-
- public DatabaseHelper(Context context) {
- super(context, DB_NAME, null, DB_VESION);
- }
-
- private static final String SQL_CREATE_TABLE_INSTALL = "CREATE TABLE IF NOT EXISTS "
- + TABLE_NAME_INSTALL
- + " ("
- + "id"
- + " INTEGER PRIMARY KEY AUTOINCREMENT,"
- + "package"
- + " TEXT,"
- + "isActive"+ " TEXT" + ");";
-
- private static final String SQL_CREATE_TABLE_IP = "CREATE TABLE IF NOT EXISTS "
- + TABLE_NAME_IP
- + " ("
- + "id"
- + " INTEGER PRIMARY KEY AUTOINCREMENT,"
- + "host"
- + " TEXT,"
- + "isActive" + " TEXT"+ ");";
-
- private static final String SQL_CREATE_TABLE_CONTACT = "CREATE TABLE IF NOT EXISTS "
- + TABLE_NAME_CONTACT
- + " ("
- + "id"
- + " INTEGER PRIMARY KEY AUTOINCREMENT,"
- + "phonenum"
- + " INTEGER,"
- + "isActive" + " TEXT"+ ");";
-
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- String sql_install = SQL_CREATE_TABLE_INSTALL;
- db.execSQL(sql_install);
-
- String sql_ip = SQL_CREATE_TABLE_IP;
- db.execSQL(sql_ip);
-
- String sql_contact = SQL_CREATE_TABLE_CONTACT;
- db.execSQL(sql_contact);
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- TXLog.i(TAG, "--whitelist.db------onUpgrade oldVersion = " + oldVersion+ "newVersion = " + newVersion);
- onCreate(db);
- }
- }
- }
- public static String takeScreenshot(final Context context,String path_name) {
- mContext = context;
- final String mImageFileName;
- synchronized (mScreenshotLock) {
- if (mScreenshotConnection != null) {
- return "";
- }
- Intent intent = new Intent();
- intent.setPackage("com.prize.txInterface");
- if(TextUtils.isEmpty(path_name)){
- long mImageTime = System.currentTimeMillis();
- String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(mImageTime));
- String default_dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()+File.separator
- +"Screenshots/";
- mImageFileName = default_dir+String.format("Screenshot_%s", imageDate);
- TXLog.d(TAG, "----takeScreenshot-------path_name==null-------mImageFileName=="+mImageFileName);
- }else {
- mImageFileName =path_name;
- TXLog.d(TAG, "----takeScreenshot---path_name!!!!==null------------mImageFileName=="+mImageFileName);
- }
- intent.setClass(context, TakeScreenshotService.class);
- ServiceConnection conn = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (mScreenshotLock) {
- if (mScreenshotConnection != this) {
- return;
- }
- TXLog.d(TAG, "----takeScreenshot--------onServiceConnected------ComponentName=="+name.toString());
- Messenger messenger = new Messenger(service);
- Message msg = Message.obtain(null, 1);
- final ServiceConnection myConn = this;
- Handler h = new Handler(TXApplication.getInstance().getHandler().getLooper()) {
- @Override
- public void handleMessage(Message msg) {
- synchronized (mScreenshotLock) {
- if (mScreenshotConnection == myConn) {
- TXLog.d(TAG,"---Handler---ServiceConnection--------------handleMessage----------------");
- Intent intent = new Intent();
- intent.setAction("screenshot.path");
- intent.putExtra("path", mImageFileName);
- context.sendBroadcast(intent);
- context.unbindService(mScreenshotConnection);
- mScreenshotConnection = null;
- TXApplication.getInstance().getHandler().removeCallbacks(mScreenshotTimeout);
- }
- }
- }
- };
- msg.replyTo = new Messenger(h);
- msg.arg1 = msg.arg2 = 0;
- msg.obj =mImageFileName;
- try {
- TXLog.d(TAG,"------ServiceConnection---------------messenger.send-----------------");
- messenger.send(msg);
- } catch (RemoteException e) {
- }
- }
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
-
- }
- };
- TXLog.d(TAG, "-----takeScreenshot----bindServiceAsUser-----------");
- if (context.bindService(intent, conn, Context.BIND_AUTO_CREATE)) {
- TXLog.d(TAG, "----takeScreenshot---bindServiceAsUser-----start------");
- mScreenshotConnection = conn;
- TXApplication.getInstance().getHandler().postDelayed(mScreenshotTimeout, 10000);
- }else {
- TXLog.d(TAG, "-----takeScreenshot----bindServiceAsUser---else--------");
- }
- }
- TXLog.d(TAG, "-----takeScreenshot--------return=="+path_name);
- return mImageFileName;
- }
-
- final static Runnable mScreenshotTimeout = new Runnable() {
- @Override public void run() {
- synchronized (mScreenshotLock) {
- if (mScreenshotConnection != null) {
- TXLog.d(TAG, "----takeScreenshot--------mScreenshotTimeout------unbindService-------------");
- if(mContext != null){
- mContext.unbindService(mScreenshotConnection);
- }
- mScreenshotConnection = null;
- }
- }
- }
- };
-
- /*
- * Copyright (C) 2011 The Android 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 com.prize.txInterface.screenshot;
-
- import com.prize.txInterface.util.TXLog;
-
- import android.app.Service;
- import android.content.Intent;
- import android.os.Handler;
- import android.os.IBinder;
- import android.os.Message;
- import android.os.Messenger;
- import android.os.RemoteException;
-
- public class TakeScreenshotService extends Service {
- private static final String TAG = "snail_TakeScreenshotService";
-
- private static GlobalScreenshot mScreenshot;
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- TXLog.d(TAG, "---------------onBind--handleMessage-----");
- switch (msg.what) {
- case 1:
- final Messenger callback = msg.replyTo;
- if (mScreenshot == null) {
- mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);
- }
- mScreenshot.takeScreenshot(new Runnable() {
- @Override public void run() {
- Message reply = Message.obtain(null, 1);
- try {
- callback.send(reply);
- } catch (RemoteException e) {
- }
- }
- }, msg.arg1 > 0, msg.arg2 > 0,(String) msg.obj);
- }
- }
- };
-
- @Override
- public IBinder onBind(Intent intent) {
- TXLog.d(TAG, "---------------onBind-------");
- return new Messenger(mHandler).getBinder();
- }
- }
-
-
- /*
- * Copyright (C) 2011 The Android 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 com.prize.txInterface.screenshot;
-
- import android.animation.Animator;
- import android.animation.AnimatorListenerAdapter;
- import android.animation.AnimatorSet;
- import android.animation.ValueAnimator;
- import android.animation.ValueAnimator.AnimatorUpdateListener;
- import android.app.Notification;
- import android.app.Notification.BigPictureStyle;
- import android.app.NotificationManager;
- import android.app.PendingIntent;
- import android.content.BroadcastReceiver;
- import android.content.ContentResolver;
- import android.content.ContentValues;
- import android.content.Context;
- import android.content.Intent;
- import android.content.res.Resources;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.ColorMatrix;
- import android.graphics.ColorMatrixColorFilter;
- import android.graphics.Matrix;
- import android.graphics.Paint;
- import android.graphics.PixelFormat;
- import android.graphics.PointF;
- import android.media.MediaActionSound;
- import android.net.Uri;
- import android.os.AsyncTask;
- import android.os.Environment;
- import android.os.Process;
- import android.os.IBinder;
- import android.provider.MediaStore;
- import android.util.DisplayMetrics;
- import android.view.Display;
- import android.view.LayoutInflater;
- import android.view.MotionEvent;
- import android.view.Surface;
- import android.view.SurfaceControl;
- import android.view.View;
- import android.view.ViewGroup;
- import android.view.WindowManager;
- import android.view.animation.Interpolator;
- import android.widget.ImageView;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.OutputStream;
- import java.text.DateFormat;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import android.content.ComponentName;
- import android.util.Log;
- import com.mediatek.storage.StorageManagerEx;
- import com.prize.txInterface.R;
- import com.prize.txInterface.R.string;
- import com.prize.txInterface.util.TXLog;
-
- /**
- * POD used in the AsyncTask which saves an image in the background.
- */
- class SaveImageInBackgroundData {
- Context context;
- Bitmap image;
- Uri imageUri;
- Runnable finisher;
- String mImagePath;
- int iconSize;
- int result;
- int previewWidth;
- int previewheight;
-
- void clearImage() {
- image = null;
- imageUri = null;
- iconSize = 0;
- }
- void clearContext() {
- context = null;
- }
- }
-
- /**
- * An AsyncTask that saves an image to the media store in the background.
- */
- class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Void,
- SaveImageInBackgroundData> {
- private static final String TAG = "snail_SaveImageInBackgroundTask";
-
- private static final String SCREENSHOTS_DIR_NAME = "Screenshots";
- private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png";
- private static final String SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)";
-
- private final int mNotificationId;
- private final NotificationManager mNotificationManager;
- private final Notification.Builder mNotificationBuilder, mPublicNotificationBuilder;
- private File mScreenshotDir;
- private final String mImageFileName;
- private final String mImageFilePath;
- private final long mImageTime;
- private final BigPictureStyle mNotificationStyle;
- private final int mImageWidth;
- private final int mImageHeight;
-
- // WORKAROUND: We want the same notification across screenshots that we update so that we don't
- // spam a user's notification drawer. However, we only show the ticker for the saving state
- // and if the ticker text is the same as the previous notification, then it will not show. So
- // for now, we just add and remove a space from the ticker text to trigger the animation when
- // necessary.
- private static boolean mTickerAddSpace;
-
- SaveImageInBackgroundTask(Context context, SaveImageInBackgroundData data,NotificationManager nManager, int nId) {
- Resources r = context.getResources();
-
- // Prepare all the output metadata
- File file = new File(StorageManagerEx.getDefaultPath(),Environment.DIRECTORY_PICTURES);
- try{
- file.mkdirs();
- if(file.exists()){
- mScreenshotDir = new File(file.toString() , SCREENSHOTS_DIR_NAME);
- } else {
- mScreenshotDir = new File(Environment.getExternalStoragePublicDirectory(
- Environment.DIRECTORY_PICTURES), SCREENSHOTS_DIR_NAME);
- }
- }catch (Exception e) {
- Log.d(TAG, "save-Exception:"+e.toString());
- }
- TXLog.d(TAG,"SaveImageInBackgroundTask mScreenshotDir "+mScreenshotDir);
-
- mImageTime = System.currentTimeMillis();
- mImageFilePath = data.mImagePath;
- String picdir = new File(mImageFilePath).getParent();
- File rootdirFile = new File(picdir);
- if(!rootdirFile.exists()){
- rootdirFile.mkdirs();
- }
- mImageFileName = mImageFilePath.substring(mImageFilePath.lastIndexOf("/") + 1,mImageFilePath.lastIndexOf("."));
- TXLog.d(TAG,"----------SaveImageInBackgroundTask---mImageFilePath="+mImageFilePath+" picdir=="+picdir+" mImageFileName=="+mImageFileName);
- // Create the large notification icon
- mImageWidth = data.image.getWidth();
- mImageHeight = data.image.getHeight();
- int iconSize = data.iconSize;
- int previewWidth = data.previewWidth;
- int previewHeight = data.previewheight;
-
- Canvas c = new Canvas();
- Paint paint = new Paint();
- ColorMatrix desat = new ColorMatrix();
- /*Prize scale the screenshot picture with no scrim color liyao 20150708 start*/
- // desat.setSaturation(0.25f);
- paint.setColorFilter(new ColorMatrixColorFilter(desat));
- Matrix matrix = new Matrix();
- int overlayColor = 0x40FFFFFF;
-
- Bitmap picture = Bitmap.createBitmap(previewWidth, previewHeight, data.image.getConfig());
- matrix.setTranslate((previewWidth - mImageWidth) / 2, (previewHeight - mImageHeight) / 2);
- c.setBitmap(picture);
- c.drawBitmap(data.image, matrix, paint);
- //c.drawColor(0x40FFFFFF);
- /*Prize scale the screenshot picture with no scrim color liyao 20150708 end*/
- c.setBitmap(null);
-
- // Note, we can't use the preview for the small icon, since it is non-square
- float scale = (float) iconSize / Math.min(mImageWidth, mImageHeight);
- Bitmap icon = Bitmap.createBitmap(iconSize, iconSize, data.image.getConfig());
- matrix.setScale(scale, scale);
- matrix.postTranslate((iconSize - (scale * mImageWidth)) / 2,
- (iconSize - (scale * mImageHeight)) / 2);
- c.setBitmap(icon);
- c.drawBitmap(data.image, matrix, paint);
- c.drawColor(overlayColor);
- c.setBitmap(null);
-
- // Show the intermediate notification
- mTickerAddSpace = !mTickerAddSpace;
- mNotificationId = nId;
- mNotificationManager = nManager;
- final long now = System.currentTimeMillis();
-
- mNotificationBuilder = new Notification.Builder(context)
- .setTicker(r.getString(R.string.screenshot_saving_ticker)
- + (mTickerAddSpace ? " " : ""))
- .setContentTitle(r.getString(R.string.screenshot_saving_title))
- .setContentText(r.getString(R.string.screenshot_saving_text))
- /*PRIZE-screenshot notification icon- liufan-2016-07-14-start*/
- .setSmallIcon(R.drawable.stat_notify_image_prize)
- /*PRIZE-screenshot notification icon- liufan-2016-07-14-end*/
- .setWhen(now)
- .setColor(r.getColor(com.android.internal.R.color.system_notification_accent_color));
-
- mNotificationStyle = new Notification.BigPictureStyle()
- .bigPicture(picture.createAshmemBitmap());
- mNotificationBuilder.setStyle(mNotificationStyle);
-
- // For "public" situations we want to show all the same info but
- // omit the actual screenshot image.
- mPublicNotificationBuilder = new Notification.Builder(context)
- .setContentTitle(r.getString(R.string.screenshot_saving_title))
- .setContentText(r.getString(R.string.screenshot_saving_text))
- /*PRIZE-screenshot notification icon- liufan-2016-07-14-start*/
- .setSmallIcon(R.drawable.stat_notify_image_prize)
- /*PRIZE-screenshot notification icon- liufan-2016-07-14-end*/
- .setCategory(Notification.CATEGORY_PROGRESS)
- .setWhen(now)
- .setColor(r.getColor(
- com.android.internal.R.color.system_notification_accent_color));
-
- /*PRIZE-don't change screenshot notification icon- liufan-2016-07-14-start*/
- Notification pn = mPublicNotificationBuilder.build();
- pn.flags |= Notification.FLAG_KEEP_NOTIFICATION_ICON;
- mNotificationBuilder.setPublicVersion(pn);
- /*PRIZE-don't change screenshot notification icon- liufan-2016-07-14-end*/
-
- Notification n = mNotificationBuilder.build();
- n.flags |= Notification.FLAG_NO_CLEAR;
- /*PRIZE-don't change screenshot notification icon- liufan-2016-07-14-start*/
- n.flags |= Notification.FLAG_KEEP_NOTIFICATION_ICON;
- /*PRIZE-don't change screenshot notification icon- liufan-2016-07-14-end*/
- mNotificationManager.notify(nId, n);
-
- // On the tablet, the large icon makes the notification appear as if it is clickable (and
- // on small devices, the large icon is not shown) so defer showing the large icon until
- // we compose the final post-save notification below.
- mNotificationBuilder.setLargeIcon(icon.createAshmemBitmap());
- // But we still don't set it for the expanded view, allowing the smallIcon to show here.
- mNotificationStyle.bigLargeIcon((Bitmap) null);
- }
-
- @Override
- protected SaveImageInBackgroundData doInBackground(SaveImageInBackgroundData... params) {
- if (params.length != 1) return null;
- if (isCancelled()) {
- params[0].clearImage();
- params[0].clearContext();
- return null;
- }
-
- // By default, AsyncTask sets the worker thread to have background thread priority, so bump
- // it back up so that we save a little quicker.
- Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
-
- Context context = params[0].context;
- Bitmap image = params[0].image;
- Resources r = context.getResources();
-
- try {
- // Create screenshot directory if it doesn't exist
- mScreenshotDir.mkdirs();
-
- // media provider uses seconds for DATE_MODIFIED and DATE_ADDED, but milliseconds
- // for DATE_TAKEN
- long dateSeconds = mImageTime / 1000;
-
- // Save
- OutputStream out = new FileOutputStream(mImageFilePath);
- image.compress(Bitmap.CompressFormat.PNG, 100, out);
- out.flush();
- out.close();
-
- // Save the screenshot to the MediaStore
- ContentValues values = new ContentValues();
- ContentResolver resolver = context.getContentResolver();
- values.put(MediaStore.Images.ImageColumns.DATA, mImageFilePath);
- values.put(MediaStore.Images.ImageColumns.TITLE, mImageFileName);
- values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, mImageFileName);
- values.put(MediaStore.Images.ImageColumns.DATE_ADDED, dateSeconds);
- values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, dateSeconds);
- values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/png");
- values.put(MediaStore.Images.ImageColumns.WIDTH, mImageWidth);
- values.put(MediaStore.Images.ImageColumns.HEIGHT, mImageHeight);
- values.put(MediaStore.Images.ImageColumns.SIZE, new File(mImageFilePath).length());
- Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
-
- // Create a share intent
- String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
- String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
- Intent sharingIntent = new Intent(Intent.ACTION_SEND);
- sharingIntent.setType("image/png");
- sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
- sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
-
- // Create a share action for the notification
- final PendingIntent callback = PendingIntent.getBroadcast(context, 0,
- new Intent(context, GlobalScreenshot.TargetChosenReceiver.class)
- .putExtra(GlobalScreenshot.CANCEL_ID, mNotificationId),
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
- Intent chooserIntent = Intent.createChooser(sharingIntent, null,
- callback.getIntentSender());
- chooserIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
- | Intent.FLAG_ACTIVITY_NEW_TASK);
- mNotificationBuilder.addAction(R.drawable.ic_screenshot_share_prize,
- r.getString(com.android.internal.R.string.share),
- PendingIntent.getActivity(context, 0, chooserIntent,
- PendingIntent.FLAG_CANCEL_CURRENT));
-
- // Create a delete action for the notification
- final PendingIntent deleteAction = PendingIntent.getBroadcast(context, 0,
- new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class)
- .putExtra(GlobalScreenshot.CANCEL_ID, mNotificationId)
- .putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()),
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);