android 接口(1)

 

Android AIDL 實現兩個APP之間的跨進程通信實例

1 Service端創建

首先需要創建一個Android工程然後創建AIDL文件,創建AIDL文件主要爲了生成繼承了Binder的Stub類,以便應用Binder進行進程間通信

servier端結構如下 
Server端結構

AIDL代碼如下


  1. // IBookManager.aidl
  2. package com.example.bookserver.aidl;
  3. // Declare any non-default types here with import statements
  4. import com.example.bookserver.aidl.Book;
  5. interface IBookManager {
  6. /**
  7. * Demonstrates some basic types that you can use as parameters
  8. * and return values in AIDL.
  9. */
  10. void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
  11. double aDouble, String aString);
  12. List<Book> getBook();
  13. boolean addBook(in Book book);
  14. }

之後創建一個實現了Parcelable的Book.java類用來傳遞數據

  1. package com.example.bookserver.aidl;
  2. import android.os.Parcel;
  3. import android.os.Parcelable;
  4. /**
  5. * Created by SAMSUNG on 2016-09-07.
  6. */
  7. public class Book implements Parcelable {
  8. private int id;
  9. private String name ;
  10. public int getId() {
  11. return id;
  12. }
  13. public void setId(int id) {
  14. this.id = id;
  15. }
  16. public String getName() {
  17. return name;
  18. }
  19. public void setName(String name) {
  20. this.name = name;
  21. }
  22. @Override
  23. public String toString() {
  24. return "Book{" +
  25. "id=" + id +
  26. ", name='" + name + '\'' +
  27. '}';
  28. }
  29. @Override
  30. public int describeContents() {
  31. return 0;
  32. }
  33. @Override
  34. public void writeToParcel(Parcel dest, int flags) {
  35. dest.writeInt(this.id);
  36. dest.writeString(this.name);
  37. }
  38. public Book() {
  39. }
  40. protected Book(Parcel in) {
  41. this.id = in.readInt();
  42. this.name = in.readString();
  43. }
  44. public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {
  45. @Override
  46. public Book createFromParcel(Parcel source) {
  47. return new Book(source);
  48. }
  49. @Override
  50. public Book[] newArray(int size) {
  51. return new Book[size];
  52. }
  53. };
  54. }
最後我們來寫一個Service用於客戶端綁定


  1. package com.example.bookserver.service;
  2. import android.app.Service;
  3. import android.content.Intent;
  4. import android.os.Binder;
  5. import android.os.IBinder;
  6. import android.os.RemoteException;
  7. import com.example.bookserver.aidl.Book;
  8. import com.example.bookserver.aidl.IBookManager;
  9. import java.util.List;
  10. import java.util.concurrent.CopyOnWriteArrayList;
  11. public class BookService extends Service {
  12. private CopyOnWriteArrayList<Book> boookList = new CopyOnWriteArrayList<Book>();
  13. public BookService() {
  14. }
  15. Binder binder = new IBookManager.Stub(){
  16. @Override
  17. public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
  18. }
  19. @Override
  20. public List<Book> getBook() throws RemoteException {
  21. return boookList;
  22. }
  23. @Override
  24. public boolean addBook(Book book) throws RemoteException {
  25. return boookList.add(book);
  26. }
  27. };
  28. @Override
  29. public IBinder onBind(Intent intent) {
  30. return binder;
  31. }
  32. @Override
  33. public void onCreate() {
  34. super.onCreate();
  35. Book book = new Book();
  36. book.setId(12345);
  37. book.setName("Book 1");
  38. boookList.add(book);
  39. }
  40. }

這樣Server端就搞定了,接下來就該進行Client端的代碼編寫了

2 Client端

Client端結構如下

Client端結構 
首先我們要講AndroidStudio 通過AIDL生成的Binder導入到Client中並將Book.java也導入到Client中 
然後寫進行Service的綁定


  1. package com.example.bookclient;
  2. import android.app.Service;
  3. import android.content.ComponentName;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.content.ServiceConnection;
  7. import android.content.pm.PackageManager;
  8. import android.content.pm.ResolveInfo;
  9. import android.os.IBinder;
  10. import android.util.Log;
  11. import com.example.bookserver.aidl.IBookManager;
  12. import java.util.List;
  13. /**
  14. * Created by SAMSUNG on 2016-09-07.
  15. */
  16. public class BookServiceManager {
  17. Context mContext = null;
  18. IBookManager mService = null;
  19. private static BookServiceManager bsm ;
  20. public static BookServiceManager getInstance(Context context){
  21. if(bsm==null){
  22. bsm = new BookServiceManager(context);
  23. }
  24. return bsm;
  25. }
  26. public IBookManager getBookServie(){
  27. if(mService==null){
  28. Log.d("BookServiceManager", "getBookServie: ");
  29. this.connectService();
  30. }
  31. return mService;
  32. }
  33. public BookServiceManager(Context mContext) {
  34. this.mContext = mContext;
  35. }
  36. ServiceConnection scc = new ServiceConnection() {
  37. @Override
  38. public void onServiceConnected(ComponentName name, IBinder service) {
  39. Log.d("BookServiceManager", "getBookServie: 2 ==> Bind ");
  40. mService = IBookManager.Stub.asInterface(service);
  41. }
  42. @Override
  43. public void onServiceDisconnected(ComponentName name) {
  44. mService = null;
  45. }
  46. };
  47. public boolean connectService(){
  48. if(mService == null){
  49. Log.d("BookServiceManager", "getBookServie: 2");
  50. Intent intent = new Intent("com.example.bookserver.service.BookService");
  51. final Intent eintent = new Intent(createExplicitFromImplicitIntent(mContext,intent));
  52. mContext.bindService(eintent,scc, Service.BIND_AUTO_CREATE);
  53. }
  54. return true;
  55. }
  56. public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
  57. // Retrieve all services that can match the given intent
  58. PackageManager pm = context.getPackageManager();
  59. List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
  60. // Make sure only one match was found
  61. if (resolveInfo == null || resolveInfo.size() != 1) {
  62. return null;
  63. }
  64. // Get component info and create ComponentName
  65. ResolveInfo serviceInfo = resolveInfo.get(0);
  66. String packageName = serviceInfo.serviceInfo.packageName;
  67. String className = serviceInfo.serviceInfo.name;
  68. ComponentName component = new ComponentName(packageName, className);
  69. // Create a new intent. Use the old one for extras and such reuse
  70. Intent explicitIntent = new Intent(implicitIntent);
  71. // Set the component to be explicit
  72. explicitIntent.setComponent(component);
  73. return explicitIntent;
  74. }
  75. }

最後對設置Button進行調用

  1. package com.example.bookclient;
  2. import android.os.Bundle;
  3. import android.os.RemoteException;
  4. import android.support.v7.app.AppCompatActivity;
  5. import android.util.Log;
  6. import android.view.View;
  7. import android.widget.Button;
  8. import com.example.bookserver.aidl.Book;
  9. import com.example.bookserver.aidl.IBookManager;
  10. public class MainActivity extends AppCompatActivity {
  11. IBookManager mBookService ;
  12. @Override
  13. protected void onCreate(Bundle savedInstanceState) {
  14. super.onCreate(savedInstanceState);
  15. setContentView(R.layout.activity_main);
  16. Button button = (Button) findViewById(R.id.button);
  17. Button addButton = (Button) findViewById(R.id.button3);
  18. Button findButton = (Button) findViewById(R.id.button2);
  19. BookServiceManager.getInstance(getApplication()).connectService();
  20. button.setOnClickListener(new View.OnClickListener(){
  21. @Override
  22. public void onClick(View v) {
  23. mBookService = BookServiceManager.getInstance(getApplication()).getBookServie();
  24. }
  25. });
  26. addButton.setOnClickListener(new View.OnClickListener(){
  27. @Override
  28. public void onClick(View v) {
  29. Book book = new Book();
  30. book.setId(2345);
  31. book.setName("add book!!");
  32. try {
  33. mBookService.addBook(book);
  34. } catch (RemoteException e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. });
  39. findButton.setOnClickListener(new View.OnClickListener(){
  40. @Override
  41. public void onClick(View v) {
  42. try {
  43. Log.d("MainActivity", mBookService.getBook().toString());
  44. } catch (RemoteException e) {
  45. e.printStackTrace();
  46. }
  47. }
  48. });
  49. }
  50. }


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)獲取聯繫人白名單接口

  1. package com.prize.txInterface.util;
  2. import com.prize.txInterface.application.TXApplication;
  3. import android.util.Log;
  4. public class TXLog {
  5. public static int d(String tag, String msg) {
  6. if (TXApplication.DEBUG) {
  7. return Log.d(tag, msg+getFunctionName());
  8. } else {
  9. return 0;
  10. }
  11. }
  12. public static int i(String tag, String msg) {
  13. if (TXApplication.DEBUG) {
  14. return Log.d(tag, msg+getFunctionName());
  15. } else {
  16. return 0;
  17. }
  18. }
  19. public static int e(String tag, String msg) {
  20. if (TXApplication.DEBUG) {
  21. return Log.e(tag, msg+getFunctionName());
  22. } else {
  23. return 0;
  24. }
  25. }
  26. /**
  27. * 方便日誌定位
  28. * add by mafei
  29. * @param tag 標籤
  30. * @return
  31. */
  32. private static String getFunctionName()
  33. {
  34. StackTraceElement[] sts = Thread.currentThread().getStackTrace();
  35. if(sts == null)
  36. {
  37. return null;
  38. }
  39. for(StackTraceElement st : sts)
  40. {
  41. if(st.isNativeMethod())
  42. {
  43. continue;
  44. }
  45. if(st.getClassName().equals(Thread.class.getName()))
  46. {
  47. continue;
  48. }
  49. if(st.getClassName().equals(TXLog.class.getName()))
  50. {
  51. continue;
  52. }
  53. return "[" + Thread.currentThread().getName() + ": "
  54. + st.getFileName() + ":" + st.getLineNumber() + " "
  55. + st.getMethodName() + " ]";
  56. }
  57. return null;
  58. }
  59. }

  1. package com.prize.txInterface.provider;
  2. import com.prize.txInterface.util.TXLog;
  3. import android.content.ContentProvider;
  4. import android.content.ContentResolver;
  5. import android.content.ContentValues;
  6. import android.content.Context;
  7. import android.content.UriMatcher;
  8. import android.database.Cursor;
  9. import android.database.sqlite.SQLiteDatabase;
  10. import android.database.sqlite.SQLiteOpenHelper;
  11. import android.net.Uri;
  12. public class PrizeWhiteListProvider extends ContentProvider{
  13. public static final String TAG = "snail_PrizeWhiteListProvider";
  14. public static final String DB_NAME = "whitelist.db";
  15. public static final int DB_VESION = 1;
  16. public static Uri CONTENT_URI_INSTALL = null;
  17. public static Uri CONTENT_URI_IP = null;
  18. public static Uri CONTENT_URI_CONTACT = null;
  19. private static UriMatcher sUriMatcher;
  20. public static final String TABLE_NAME_INSTALL = "install";
  21. public static final String TABLE_NAME_IP = "ip";
  22. public static final String TABLE_NAME_CONTACT = "contact";
  23. private static final int _INSTALL = 1;
  24. private static final int _IP = 2;
  25. private static final int _CONTACT = 3;
  26. private ContentResolver mContentResolver;
  27. static DatabaseHelper mOpenHelper;
  28. static SQLiteDatabase db;
  29. public static SQLiteDatabase getDbInstance(Context context){
  30. TXLog.i(TAG, "--whitelist.db-----onCreate----getDbInstance---- ");
  31. if(db==null)
  32. {
  33. mOpenHelper = new DatabaseHelper(context);
  34. db = mOpenHelper.getReadableDatabase();
  35. }
  36. return db;
  37. }
  38. @Override
  39. public boolean onCreate() {
  40. // TODO Auto-generated method stub
  41. TXLog.i(TAG, "--whitelist.db-----onCreate-- ");
  42. String db_auth = getContext().getPackageName() + ".provider";
  43. CONTENT_URI_INSTALL = Uri.parse("content://" + db_auth + "/"+ TABLE_NAME_INSTALL);
  44. CONTENT_URI_IP = Uri.parse("content://" + db_auth + "/"+ TABLE_NAME_IP);
  45. CONTENT_URI_CONTACT = Uri.parse("content://" + db_auth + "/"+ TABLE_NAME_CONTACT);
  46. sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  47. sUriMatcher.addURI(db_auth, TABLE_NAME_INSTALL, _INSTALL);
  48. sUriMatcher.addURI(db_auth, TABLE_NAME_IP, _IP);
  49. sUriMatcher.addURI(db_auth, TABLE_NAME_CONTACT, _CONTACT);
  50. getDbInstance(this.getContext());
  51. mContentResolver = getContext().getContentResolver();
  52. return true;
  53. }
  54. @Override
  55. public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {
  56. // TODO Auto-generated method stub
  57. Cursor cur = null;
  58. String tableName = getTableName(uri);
  59. TXLog.i(TAG, "--whitelist.db-----query tableName = " + tableName+ " selection = " + selection);
  60. cur = db.query(tableName, projection, selection, selectionArgs, null,null, sortOrder);
  61. return cur;
  62. }
  63. @Override
  64. public String getType(Uri uri) {
  65. // TODO Auto-generated method stub
  66. throw new IllegalArgumentException("Uri IllegalArgument:" + uri);
  67. }
  68. @Override
  69. public Uri insert(Uri uri, ContentValues values) {
  70. // TODO Auto-generated method stub
  71. long id = -1;
  72. String tableName = getTableName(uri);
  73. TXLog.i(TAG, "--whitelist.db-----insert tableName = " + tableName);
  74. id = db.insert(tableName, "Content is empty", values);
  75. if (id == -1) {
  76. return null;
  77. }
  78. return Uri.parse("" + id);
  79. }
  80. @Override
  81. public int delete(Uri uri, String selection, String[] selectionArgs) {
  82. // TODO Auto-generated method stub
  83. int num = 0;
  84. String tableName = getTableName(uri);
  85. TXLog.i(TAG, "--whitelist.db-----delete tableName = " + tableName+ "selection = " + selection);
  86. num = db.delete(tableName, selection, selectionArgs);
  87. return num;
  88. }
  89. @Override
  90. public int update(Uri uri, ContentValues values, String selection,
  91. String[] selectionArgs) {
  92. // TODO Auto-generated method stub
  93. int num = 0;
  94. String tableName = getTableName(uri);
  95. TXLog.i(TAG, "--whitelist.db-----update tableName = " + tableName+ "selection = " + selection);
  96. num = db.update(tableName, values, selection, selectionArgs);
  97. return num;
  98. }
  99. public String getTableName(Uri uri) {
  100. switch (sUriMatcher.match(uri)) {
  101. case _INSTALL://
  102. return TABLE_NAME_INSTALL;
  103. case _IP://
  104. return TABLE_NAME_IP;
  105. case _CONTACT://
  106. return TABLE_NAME_CONTACT;
  107. default:
  108. return null;
  109. }
  110. }
  111. public static class DatabaseHelper extends SQLiteOpenHelper {
  112. public DatabaseHelper(Context context) {
  113. super(context, DB_NAME, null, DB_VESION);
  114. }
  115. private static final String SQL_CREATE_TABLE_INSTALL = "CREATE TABLE IF NOT EXISTS "
  116. + TABLE_NAME_INSTALL
  117. + " ("
  118. + "id"
  119. + " INTEGER PRIMARY KEY AUTOINCREMENT,"
  120. + "package"
  121. + " TEXT,"
  122. + "isActive"+ " TEXT" + ");";
  123. private static final String SQL_CREATE_TABLE_IP = "CREATE TABLE IF NOT EXISTS "
  124. + TABLE_NAME_IP
  125. + " ("
  126. + "id"
  127. + " INTEGER PRIMARY KEY AUTOINCREMENT,"
  128. + "host"
  129. + " TEXT,"
  130. + "isActive" + " TEXT"+ ");";
  131. private static final String SQL_CREATE_TABLE_CONTACT = "CREATE TABLE IF NOT EXISTS "
  132. + TABLE_NAME_CONTACT
  133. + " ("
  134. + "id"
  135. + " INTEGER PRIMARY KEY AUTOINCREMENT,"
  136. + "phonenum"
  137. + " INTEGER,"
  138. + "isActive" + " TEXT"+ ");";
  139. @Override
  140. public void onCreate(SQLiteDatabase db) {
  141. String sql_install = SQL_CREATE_TABLE_INSTALL;
  142. db.execSQL(sql_install);
  143. String sql_ip = SQL_CREATE_TABLE_IP;
  144. db.execSQL(sql_ip);
  145. String sql_contact = SQL_CREATE_TABLE_CONTACT;
  146. db.execSQL(sql_contact);
  147. }
  148. @Override
  149. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  150. TXLog.i(TAG, "--whitelist.db------onUpgrade oldVersion = " + oldVersion+ "newVersion = " + newVersion);
  151. onCreate(db);
  152. }
  153. }
  154. }

1) 截屏接口


  1. public static String takeScreenshot(final Context context,String path_name) {
  2. mContext = context;
  3. final String mImageFileName;
  4. synchronized (mScreenshotLock) {
  5. if (mScreenshotConnection != null) {
  6. return "";
  7. }
  8. Intent intent = new Intent();
  9. intent.setPackage("com.prize.txInterface");
  10. if(TextUtils.isEmpty(path_name)){
  11. long mImageTime = System.currentTimeMillis();
  12. String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(mImageTime));
  13. String default_dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()+File.separator
  14. +"Screenshots/";
  15. mImageFileName = default_dir+String.format("Screenshot_%s", imageDate);
  16. TXLog.d(TAG, "----takeScreenshot-------path_name==null-------mImageFileName=="+mImageFileName);
  17. }else {
  18. mImageFileName =path_name;
  19. TXLog.d(TAG, "----takeScreenshot---path_name!!!!==null------------mImageFileName=="+mImageFileName);
  20. }
  21. intent.setClass(context, TakeScreenshotService.class);
  22. ServiceConnection conn = new ServiceConnection() {
  23. @Override
  24. public void onServiceConnected(ComponentName name, IBinder service) {
  25. synchronized (mScreenshotLock) {
  26. if (mScreenshotConnection != this) {
  27. return;
  28. }
  29. TXLog.d(TAG, "----takeScreenshot--------onServiceConnected------ComponentName=="+name.toString());
  30. Messenger messenger = new Messenger(service);
  31. Message msg = Message.obtain(null, 1);
  32. final ServiceConnection myConn = this;
  33. Handler h = new Handler(TXApplication.getInstance().getHandler().getLooper()) {
  34. @Override
  35. public void handleMessage(Message msg) {
  36. synchronized (mScreenshotLock) {
  37. if (mScreenshotConnection == myConn) {
  38. TXLog.d(TAG,"---Handler---ServiceConnection--------------handleMessage----------------");
  39. Intent intent = new Intent();
  40. intent.setAction("screenshot.path");
  41. intent.putExtra("path", mImageFileName);
  42. context.sendBroadcast(intent);
  43. context.unbindService(mScreenshotConnection);
  44. mScreenshotConnection = null;
  45. TXApplication.getInstance().getHandler().removeCallbacks(mScreenshotTimeout);
  46. }
  47. }
  48. }
  49. };
  50. msg.replyTo = new Messenger(h);
  51. msg.arg1 = msg.arg2 = 0;
  52. msg.obj =mImageFileName;
  53. try {
  54. TXLog.d(TAG,"------ServiceConnection---------------messenger.send-----------------");
  55. messenger.send(msg);
  56. } catch (RemoteException e) {
  57. }
  58. }
  59. }
  60. @Override
  61. public void onServiceDisconnected(ComponentName name) {
  62. }
  63. };
  64. TXLog.d(TAG, "-----takeScreenshot----bindServiceAsUser-----------");
  65. if (context.bindService(intent, conn, Context.BIND_AUTO_CREATE)) {
  66. TXLog.d(TAG, "----takeScreenshot---bindServiceAsUser-----start------");
  67. mScreenshotConnection = conn;
  68. TXApplication.getInstance().getHandler().postDelayed(mScreenshotTimeout, 10000);
  69. }else {
  70. TXLog.d(TAG, "-----takeScreenshot----bindServiceAsUser---else--------");
  71. }
  72. }
  73. TXLog.d(TAG, "-----takeScreenshot--------return=="+path_name);
  74. return mImageFileName;
  75. }
  76. final static Runnable mScreenshotTimeout = new Runnable() {
  77. @Override public void run() {
  78. synchronized (mScreenshotLock) {
  79. if (mScreenshotConnection != null) {
  80. TXLog.d(TAG, "----takeScreenshot--------mScreenshotTimeout------unbindService-------------");
  81. if(mContext != null){
  82. mContext.unbindService(mScreenshotConnection);
  83. }
  84. mScreenshotConnection = null;
  85. }
  86. }
  87. }
  88. };
  89. /*
  90. * Copyright (C) 2011 The Android Open Source Project
  91. *
  92. * Licensed under the Apache License, Version 2.0 (the "License");
  93. * you may not use this file except in compliance with the License.
  94. * You may obtain a copy of the License at
  95. *
  96. * http://www.apache.org/licenses/LICENSE-2.0
  97. *
  98. * Unless required by applicable law or agreed to in writing, software
  99. * distributed under the License is distributed on an "AS IS" BASIS,
  100. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  101. * See the License for the specific language governing permissions and
  102. * limitations under the License.
  103. */
  104. package com.prize.txInterface.screenshot;
  105. import com.prize.txInterface.util.TXLog;
  106. import android.app.Service;
  107. import android.content.Intent;
  108. import android.os.Handler;
  109. import android.os.IBinder;
  110. import android.os.Message;
  111. import android.os.Messenger;
  112. import android.os.RemoteException;
  113. public class TakeScreenshotService extends Service {
  114. private static final String TAG = "snail_TakeScreenshotService";
  115. private static GlobalScreenshot mScreenshot;
  116. private Handler mHandler = new Handler() {
  117. @Override
  118. public void handleMessage(Message msg) {
  119. TXLog.d(TAG, "---------------onBind--handleMessage-----");
  120. switch (msg.what) {
  121. case 1:
  122. final Messenger callback = msg.replyTo;
  123. if (mScreenshot == null) {
  124. mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);
  125. }
  126. mScreenshot.takeScreenshot(new Runnable() {
  127. @Override public void run() {
  128. Message reply = Message.obtain(null, 1);
  129. try {
  130. callback.send(reply);
  131. } catch (RemoteException e) {
  132. }
  133. }
  134. }, msg.arg1 > 0, msg.arg2 > 0,(String) msg.obj);
  135. }
  136. }
  137. };
  138. @Override
  139. public IBinder onBind(Intent intent) {
  140. TXLog.d(TAG, "---------------onBind-------");
  141. return new Messenger(mHandler).getBinder();
  142. }
  143. }
  144. /*
  145. * Copyright (C) 2011 The Android Open Source Project
  146. *
  147. * Licensed under the Apache License, Version 2.0 (the "License");
  148. * you may not use this file except in compliance with the License.
  149. * You may obtain a copy of the License at
  150. *
  151. * http://www.apache.org/licenses/LICENSE-2.0
  152. *
  153. * Unless required by applicable law or agreed to in writing, software
  154. * distributed under the License is distributed on an "AS IS" BASIS,
  155. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  156. * See the License for the specific language governing permissions and
  157. * limitations under the License.
  158. */
  159. package com.prize.txInterface.screenshot;
  160. import android.animation.Animator;
  161. import android.animation.AnimatorListenerAdapter;
  162. import android.animation.AnimatorSet;
  163. import android.animation.ValueAnimator;
  164. import android.animation.ValueAnimator.AnimatorUpdateListener;
  165. import android.app.Notification;
  166. import android.app.Notification.BigPictureStyle;
  167. import android.app.NotificationManager;
  168. import android.app.PendingIntent;
  169. import android.content.BroadcastReceiver;
  170. import android.content.ContentResolver;
  171. import android.content.ContentValues;
  172. import android.content.Context;
  173. import android.content.Intent;
  174. import android.content.res.Resources;
  175. import android.graphics.Bitmap;
  176. import android.graphics.Canvas;
  177. import android.graphics.ColorMatrix;
  178. import android.graphics.ColorMatrixColorFilter;
  179. import android.graphics.Matrix;
  180. import android.graphics.Paint;
  181. import android.graphics.PixelFormat;
  182. import android.graphics.PointF;
  183. import android.media.MediaActionSound;
  184. import android.net.Uri;
  185. import android.os.AsyncTask;
  186. import android.os.Environment;
  187. import android.os.Process;
  188. import android.os.IBinder;
  189. import android.provider.MediaStore;
  190. import android.util.DisplayMetrics;
  191. import android.view.Display;
  192. import android.view.LayoutInflater;
  193. import android.view.MotionEvent;
  194. import android.view.Surface;
  195. import android.view.SurfaceControl;
  196. import android.view.View;
  197. import android.view.ViewGroup;
  198. import android.view.WindowManager;
  199. import android.view.animation.Interpolator;
  200. import android.widget.ImageView;
  201. import java.io.File;
  202. import java.io.FileOutputStream;
  203. import java.io.OutputStream;
  204. import java.text.DateFormat;
  205. import java.text.SimpleDateFormat;
  206. import java.util.Date;
  207. import android.content.ComponentName;
  208. import android.util.Log;
  209. import com.mediatek.storage.StorageManagerEx;
  210. import com.prize.txInterface.R;
  211. import com.prize.txInterface.R.string;
  212. import com.prize.txInterface.util.TXLog;
  213. /**
  214. * POD used in the AsyncTask which saves an image in the background.
  215. */
  216. class SaveImageInBackgroundData {
  217. Context context;
  218. Bitmap image;
  219. Uri imageUri;
  220. Runnable finisher;
  221. String mImagePath;
  222. int iconSize;
  223. int result;
  224. int previewWidth;
  225. int previewheight;
  226. void clearImage() {
  227. image = null;
  228. imageUri = null;
  229. iconSize = 0;
  230. }
  231. void clearContext() {
  232. context = null;
  233. }
  234. }
  235. /**
  236. * An AsyncTask that saves an image to the media store in the background.
  237. */
  238. class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Void,
  239. SaveImageInBackgroundData> {
  240. private static final String TAG = "snail_SaveImageInBackgroundTask";
  241. private static final String SCREENSHOTS_DIR_NAME = "Screenshots";
  242. private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png";
  243. private static final String SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)";
  244. private final int mNotificationId;
  245. private final NotificationManager mNotificationManager;
  246. private final Notification.Builder mNotificationBuilder, mPublicNotificationBuilder;
  247. private File mScreenshotDir;
  248. private final String mImageFileName;
  249. private final String mImageFilePath;
  250. private final long mImageTime;
  251. private final BigPictureStyle mNotificationStyle;
  252. private final int mImageWidth;
  253. private final int mImageHeight;
  254. // WORKAROUND: We want the same notification across screenshots that we update so that we don't
  255. // spam a user's notification drawer. However, we only show the ticker for the saving state
  256. // and if the ticker text is the same as the previous notification, then it will not show. So
  257. // for now, we just add and remove a space from the ticker text to trigger the animation when
  258. // necessary.
  259. private static boolean mTickerAddSpace;
  260. SaveImageInBackgroundTask(Context context, SaveImageInBackgroundData data,NotificationManager nManager, int nId) {
  261. Resources r = context.getResources();
  262. // Prepare all the output metadata
  263. File file = new File(StorageManagerEx.getDefaultPath(),Environment.DIRECTORY_PICTURES);
  264. try{
  265. file.mkdirs();
  266. if(file.exists()){
  267. mScreenshotDir = new File(file.toString() , SCREENSHOTS_DIR_NAME);
  268. } else {
  269. mScreenshotDir = new File(Environment.getExternalStoragePublicDirectory(
  270. Environment.DIRECTORY_PICTURES), SCREENSHOTS_DIR_NAME);
  271. }
  272. }catch (Exception e) {
  273. Log.d(TAG, "save-Exception:"+e.toString());
  274. }
  275. TXLog.d(TAG,"SaveImageInBackgroundTask mScreenshotDir "+mScreenshotDir);
  276. mImageTime = System.currentTimeMillis();
  277. mImageFilePath = data.mImagePath;
  278. String picdir = new File(mImageFilePath).getParent();
  279. File rootdirFile = new File(picdir);
  280. if(!rootdirFile.exists()){
  281. rootdirFile.mkdirs();
  282. }
  283. mImageFileName = mImageFilePath.substring(mImageFilePath.lastIndexOf("/") + 1,mImageFilePath.lastIndexOf("."));
  284. TXLog.d(TAG,"----------SaveImageInBackgroundTask---mImageFilePath="+mImageFilePath+" picdir=="+picdir+" mImageFileName=="+mImageFileName);
  285. // Create the large notification icon
  286. mImageWidth = data.image.getWidth();
  287. mImageHeight = data.image.getHeight();
  288. int iconSize = data.iconSize;
  289. int previewWidth = data.previewWidth;
  290. int previewHeight = data.previewheight;
  291. Canvas c = new Canvas();
  292. Paint paint = new Paint();
  293. ColorMatrix desat = new ColorMatrix();
  294. /*Prize scale the screenshot picture with no scrim color liyao 20150708 start*/
  295. // desat.setSaturation(0.25f);
  296. paint.setColorFilter(new ColorMatrixColorFilter(desat));
  297. Matrix matrix = new Matrix();
  298. int overlayColor = 0x40FFFFFF;
  299. Bitmap picture = Bitmap.createBitmap(previewWidth, previewHeight, data.image.getConfig());
  300. matrix.setTranslate((previewWidth - mImageWidth) / 2, (previewHeight - mImageHeight) / 2);
  301. c.setBitmap(picture);
  302. c.drawBitmap(data.image, matrix, paint);
  303. //c.drawColor(0x40FFFFFF);
  304. /*Prize scale the screenshot picture with no scrim color liyao 20150708 end*/
  305. c.setBitmap(null);
  306. // Note, we can't use the preview for the small icon, since it is non-square
  307. float scale = (float) iconSize / Math.min(mImageWidth, mImageHeight);
  308. Bitmap icon = Bitmap.createBitmap(iconSize, iconSize, data.image.getConfig());
  309. matrix.setScale(scale, scale);
  310. matrix.postTranslate((iconSize - (scale * mImageWidth)) / 2,
  311. (iconSize - (scale * mImageHeight)) / 2);
  312. c.setBitmap(icon);
  313. c.drawBitmap(data.image, matrix, paint);
  314. c.drawColor(overlayColor);
  315. c.setBitmap(null);
  316. // Show the intermediate notification
  317. mTickerAddSpace = !mTickerAddSpace;
  318. mNotificationId = nId;
  319. mNotificationManager = nManager;
  320. final long now = System.currentTimeMillis();
  321. mNotificationBuilder = new Notification.Builder(context)
  322. .setTicker(r.getString(R.string.screenshot_saving_ticker)
  323. + (mTickerAddSpace ? " " : ""))
  324. .setContentTitle(r.getString(R.string.screenshot_saving_title))
  325. .setContentText(r.getString(R.string.screenshot_saving_text))
  326. /*PRIZE-screenshot notification icon- liufan-2016-07-14-start*/
  327. .setSmallIcon(R.drawable.stat_notify_image_prize)
  328. /*PRIZE-screenshot notification icon- liufan-2016-07-14-end*/
  329. .setWhen(now)
  330. .setColor(r.getColor(com.android.internal.R.color.system_notification_accent_color));
  331. mNotificationStyle = new Notification.BigPictureStyle()
  332. .bigPicture(picture.createAshmemBitmap());
  333. mNotificationBuilder.setStyle(mNotificationStyle);
  334. // For "public" situations we want to show all the same info but
  335. // omit the actual screenshot image.
  336. mPublicNotificationBuilder = new Notification.Builder(context)
  337. .setContentTitle(r.getString(R.string.screenshot_saving_title))
  338. .setContentText(r.getString(R.string.screenshot_saving_text))
  339. /*PRIZE-screenshot notification icon- liufan-2016-07-14-start*/
  340. .setSmallIcon(R.drawable.stat_notify_image_prize)
  341. /*PRIZE-screenshot notification icon- liufan-2016-07-14-end*/
  342. .setCategory(Notification.CATEGORY_PROGRESS)
  343. .setWhen(now)
  344. .setColor(r.getColor(
  345. com.android.internal.R.color.system_notification_accent_color));
  346. /*PRIZE-don't change screenshot notification icon- liufan-2016-07-14-start*/
  347. Notification pn = mPublicNotificationBuilder.build();
  348. pn.flags |= Notification.FLAG_KEEP_NOTIFICATION_ICON;
  349. mNotificationBuilder.setPublicVersion(pn);
  350. /*PRIZE-don't change screenshot notification icon- liufan-2016-07-14-end*/
  351. Notification n = mNotificationBuilder.build();
  352. n.flags |= Notification.FLAG_NO_CLEAR;
  353. /*PRIZE-don't change screenshot notification icon- liufan-2016-07-14-start*/
  354. n.flags |= Notification.FLAG_KEEP_NOTIFICATION_ICON;
  355. /*PRIZE-don't change screenshot notification icon- liufan-2016-07-14-end*/
  356. mNotificationManager.notify(nId, n);
  357. // On the tablet, the large icon makes the notification appear as if it is clickable (and
  358. // on small devices, the large icon is not shown) so defer showing the large icon until
  359. // we compose the final post-save notification below.
  360. mNotificationBuilder.setLargeIcon(icon.createAshmemBitmap());
  361. // But we still don't set it for the expanded view, allowing the smallIcon to show here.
  362. mNotificationStyle.bigLargeIcon((Bitmap) null);
  363. }
  364. @Override
  365. protected SaveImageInBackgroundData doInBackground(SaveImageInBackgroundData... params) {
  366. if (params.length != 1) return null;
  367. if (isCancelled()) {
  368. params[0].clearImage();
  369. params[0].clearContext();
  370. return null;
  371. }
  372. // By default, AsyncTask sets the worker thread to have background thread priority, so bump
  373. // it back up so that we save a little quicker.
  374. Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
  375. Context context = params[0].context;
  376. Bitmap image = params[0].image;
  377. Resources r = context.getResources();
  378. try {
  379. // Create screenshot directory if it doesn't exist
  380. mScreenshotDir.mkdirs();
  381. // media provider uses seconds for DATE_MODIFIED and DATE_ADDED, but milliseconds
  382. // for DATE_TAKEN
  383. long dateSeconds = mImageTime / 1000;
  384. // Save
  385. OutputStream out = new FileOutputStream(mImageFilePath);
  386. image.compress(Bitmap.CompressFormat.PNG, 100, out);
  387. out.flush();
  388. out.close();
  389. // Save the screenshot to the MediaStore
  390. ContentValues values = new ContentValues();
  391. ContentResolver resolver = context.getContentResolver();
  392. values.put(MediaStore.Images.ImageColumns.DATA, mImageFilePath);
  393. values.put(MediaStore.Images.ImageColumns.TITLE, mImageFileName);
  394. values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, mImageFileName);
  395. values.put(MediaStore.Images.ImageColumns.DATE_ADDED, dateSeconds);
  396. values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, dateSeconds);
  397. values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/png");
  398. values.put(MediaStore.Images.ImageColumns.WIDTH, mImageWidth);
  399. values.put(MediaStore.Images.ImageColumns.HEIGHT, mImageHeight);
  400. values.put(MediaStore.Images.ImageColumns.SIZE, new File(mImageFilePath).length());
  401. Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
  402. // Create a share intent
  403. String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
  404. String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
  405. Intent sharingIntent = new Intent(Intent.ACTION_SEND);
  406. sharingIntent.setType("image/png");
  407. sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
  408. sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
  409. // Create a share action for the notification
  410. final PendingIntent callback = PendingIntent.getBroadcast(context, 0,
  411. new Intent(context, GlobalScreenshot.TargetChosenReceiver.class)
  412. .putExtra(GlobalScreenshot.CANCEL_ID, mNotificationId),
  413. PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
  414. Intent chooserIntent = Intent.createChooser(sharingIntent, null,
  415. callback.getIntentSender());
  416. chooserIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
  417. | Intent.FLAG_ACTIVITY_NEW_TASK);
  418. mNotificationBuilder.addAction(R.drawable.ic_screenshot_share_prize,
  419. r.getString(com.android.internal.R.string.share),
  420. PendingIntent.getActivity(context, 0, chooserIntent,
  421. PendingIntent.FLAG_CANCEL_CURRENT));
  422. // Create a delete action for the notification
  423. final PendingIntent deleteAction = PendingIntent.getBroadcast(context, 0,
  424. new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class)
  425. .putExtra(GlobalScreenshot.CANCEL_ID, mNotificationId)
  426. .putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()),
  427. PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
發佈了26 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章