package it.michelelacorte.androidshortcuts;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.os.UserHandle;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.DisplayMetrics;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import it.michelelacorte.androidshortcuts.util.Utils;
/**
* Created by Michele on 10/01/2017.
*/
/**
* Remote Shortcuts class provide method to serialize and deserialize shortcuts for save/get shortcuts from different apps
*/
public class RemoteShortcuts {
private static final String TAG = "RemoteShorctus";
public static boolean USE_SHORTCUTS_FROM_API_25 = false;
/**
* Save shortcuts on file
* @param activity Activity
* @param listOfShortcuts ArrayList<Shortcuts>
*/
public static void saveRemoteShortcuts(Activity activity, ArrayList<Shortcuts> listOfShortcuts){
String fileName = activity.getPackageName() + "/shortcut.shc";
ObjectOutput out = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
checkPermission(activity);
}
try {
File file = new File(Environment.getExternalStorageDirectory() + "/Shortcuts/"+fileName);
file.getParentFile().mkdirs();
file.createNewFile();
out = new ObjectOutputStream(new FileOutputStream(file, false));
for(Shortcuts shortcuts : listOfShortcuts){
if(shortcuts.getShortcutsText() != null) {
out.writeUTF(shortcuts.getShortcutsText());
}if(shortcuts.getShortcutsImage() != 0) {
Bitmap image = BitmapFactory.decodeResource(activity.getResources(), shortcuts.getShortcutsImage());
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.PNG, 100, stream);
final byte[] imageByteArray = stream.toByteArray();
out.writeInt(imageByteArray.length);
out.write(imageByteArray);
}else if (shortcuts.getShortcutsImageBitmap() != null){
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
shortcuts.getShortcutsImageBitmap().compress(Bitmap.CompressFormat.PNG, 100, stream);
final byte[] imageByteArray = stream.toByteArray();
out.writeInt(imageByteArray.length);
out.write(imageByteArray);
}
if(shortcuts.getTargetPackage() != null && shortcuts.getTargetClass() != null){
out.writeUTF(shortcuts.getTargetPackage());
out.writeUTF(shortcuts.getTargetClass());
}else{
out.writeUTF(activity.getPackageName());
out.writeUTF(activity.getPackageName()+"."+activity.getLocalClassName());
}
}
out.close();
Log.d(TAG, "Shortcuts saved into: " + Environment.getExternalStorageDirectory() + "/Shortcuts/"+fileName);
} catch (FileNotFoundException e) {
Log.e(TAG, e.toString());
} catch (IOException e) {
Log.e(TAG, e.toString());
}
}
/**
* Get shortcuts from file
* @param activity Activity
* @return ArrayList<Shotrcuts>
*/
public static ArrayList<Shortcuts> getRemoteShortcuts(Activity activity, String packageName){
String fileName = packageName + "/shortcut.shc";
ObjectInputStream input;
ArrayList<Shortcuts> listOfShortcuts = new ArrayList<>();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
checkPermission(activity);
}
try {
input = new ObjectInputStream(new FileInputStream(Environment.getExternalStorageDirectory() + "/Shortcuts/"+fileName));
try{
while(true) {
String shortcutsText = input.readUTF();
final int length = input.readInt();
final byte[] imageByteArray = new byte[length];
input.readFully(imageByteArray);
Bitmap shortcutsImage = BitmapFactory.decodeByteArray(imageByteArray, 0, length);
String targetPackage = input.readUTF();
String targetClass = input.readUTF();
listOfShortcuts.add(new Shortcuts(shortcutsImage, shortcutsText, targetClass, targetPackage, ""));
}
}catch (EOFException e){}
input.close();
} catch (StreamCorruptedException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, "Shortcuts getted from: " + Environment.getExternalStorageDirectory() + "/Shortcuts/"+fileName);
return listOfShortcuts;
}
/**
* This method get shortcuts defined by App in Android 7.1 Nougat (API 25), returned shortcuts are sorted by rank
* in according to Google Doc
* @param activity Activity
* @param targetPackageName String
* @param uid int
* @return ArrayList<Shortcuts>
* @throws Exception
*/
@TargetApi(25)
@RequiresApi(25)
public static ArrayList<Shortcuts> getRemoteShortcutsOnAPI25(Activity activity, String targetPackageName, int uid) throws Exception {
LauncherApps launcherApps = (LauncherApps) activity.getApplicationContext().getSystemService(Context.LAUNCHER_APPS_SERVICE);
if (!launcherApps.hasShortcutHostPermission()) {
Log.e(TAG, "Don't have permission, you may need set this app as default launcher!");
throw new Exception("Don't have permission, you may need set this app as default launcher!");
}
PackageManager packageManager = activity.getPackageManager();
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> resolveInfoList;
if (packageManager == null || (resolveInfoList = packageManager.queryIntentActivities(mainIntent, 0)) == null) {
Log.e(TAG, "No Main and Launcher Activity!");
throw new Exception("No Main and Launcher Activity!");
}
ArrayList<Shortcuts> shortcutsArrayList = new ArrayList<>();
int queryFlags = LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC | LauncherApps.ShortcutQuery.FLAG_MATCH_MANIFEST
| LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
List<ShortcutInfo> shortcutInfoList = launcherApps.getShortcuts(
new LauncherApps.ShortcutQuery().setPackage(targetPackageName).setQueryFlags(queryFlags),
UserHandle.getUserHandleForUid(uid));
for (int j = 0; j < shortcutInfoList.size(); j++) {
if (shortcutInfoList.get(j) != null) {
try {
//Get shortcuts text (short label)
String shortcutsText = shortcutInfoList.get(j).getShortLabel().toString();
//Get packageName
String packageName = shortcutInfoList.get(j).getActivity().getPackageName();
//Get className
String className = shortcutInfoList.get(j).getActivity().getClassName();
//Get display metrics and get shortcuts drawable
DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
Drawable shortcutsImage = launcherApps.getShortcutIconDrawable(shortcutInfoList.get(j), metrics.densityDpi);
Bitmap shortcutsImageBitmap = Utils.convertDrawableToBitmap(shortcutsImage);
//Get image badge with density adjust
Drawable shortcutsImageBadged = launcherApps.getShortcutBadgedIconDrawable(shortcutInfoList.get(j), metrics.densityDpi);
Bitmap shortcutsImageBadgedBitmap = Utils.convertDrawableToBitmap(shortcutsImageBadged);
//Get rank to order list
int rank = shortcutInfoList.get(j).getRank();
//Initialize shortcuts
shortcutsArrayList.add(new Shortcuts(shortcutsImageBitmap, shortcutsImageBadgedBitmap, shortcutsText, className, packageName, rank));
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
}
USE_SHORTCUTS_FROM_API_25 = true;
//Order by rank (lowest to highest)
Collections.sort(shortcutsArrayList, new Comparator<Shortcuts>() {
@Override
public int compare(Shortcuts shortcuts, Shortcuts shortcuts1) {
return shortcuts1.getRank() - shortcuts.getRank();
}
});
//return sorted arraylist
return shortcutsArrayList;
}
/**
* Check if user had permission
* @param activity Activity
*/
private static void checkPermission(Activity activity) {
int result = ContextCompat.checkSelfPermission(activity, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (result != PackageManager.PERMISSION_GRANTED) {
requestPermission(activity);
}
}
/**
* Make request permission
* @param activity Activity
*/
private static void requestPermission(Activity activity) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Log.d(TAG, "Write External Storage permission allows us to do store shortcuts data. Please allow this permission in App Settings.");
} else {
ActivityCompat.requestPermissions(activity, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 111);
Log.d(TAG, "Write External Storage permission allows us to do store shortcuts data.");
}
}
}