Переглянути джерело

添加有范商城快捷方式入口

zengjiebin 7 роки тому
батько
коміт
de571cf518
39 змінених файлів з 2084 додано та 28 видалено
  1. 1 0
      .idea/gradle.xml
  2. 2 0
      app/build.gradle
  3. 8 0
      app/src/main/AndroidManifest.xml
  4. 5 0
      app/src/main/java/com/sheep/gamegroup/model/api/ApiService.java
  5. 0 1
      app/src/main/java/com/sheep/gamegroup/module/game/fragment/FgtGameCenter.java
  6. 66 0
      app/src/main/java/com/sheep/gamegroup/module/game/fragment/FgtGiftCenter.java
  7. 11 1
      app/src/main/java/com/sheep/gamegroup/util/CommonUtil.java
  8. 11 1
      app/src/main/java/com/sheep/gamegroup/util/Jump2View.java
  9. 134 0
      app/src/main/java/com/sheep/gamegroup/util/SysAppUtil.java
  10. 55 21
      app/src/main/java/com/sheep/gamegroup/util/TestUtil.java
  11. 7 3
      app/src/main/java/com/sheep/gamegroup/view/activity/ActWebX5.java
  12. 23 0
      app/src/main/java/com/sheep/gamegroup/view/activity/YFActWebX5.java
  13. BIN
      app/src/main/res/drawable-xxhdpi/icon_yf.png
  14. BIN
      app/src/main/res/drawable/icon_yf_small.png
  15. 69 0
      app/src/main/res/layout/fgt_gift_center.xml
  16. BIN
      app/src/main/res/mipmap-xxhdpi/haohualb.png
  17. BIN
      app/src/main/res/mipmap-xxhdpi/haohualb_c.png
  18. BIN
      app/src/main/res/mipmap-xxhdpi/icon_yf.png
  19. BIN
      app/src/main/res/mipmap-xxhdpi/libaotj.png
  20. BIN
      app/src/main/res/mipmap-xxhdpi/libaotj_c.png
  21. BIN
      app/src/main/res/mipmap-xxhdpi/remenlb.png
  22. BIN
      app/src/main/res/mipmap-xxhdpi/remenlb_c.png
  23. BIN
      app/src/main/res/mipmap-xxhdpi/sous.png
  24. BIN
      app/src/main/res/mipmap-xxhdpi/xinshoulb.png
  25. BIN
      app/src/main/res/mipmap-xxhdpi/xinshoulb_c.png
  26. 1 1
      settings.gradle
  27. 1 0
      shortcut_lib/.gitignore
  28. 24 0
      shortcut_lib/build.gradle
  29. 17 0
      shortcut_lib/proguard-rules.pro
  30. 13 0
      shortcut_lib/src/androidTest/java/com/xys/shortcut_lib/ApplicationTest.java
  31. 235 0
      shortcut_lib/src/main/AndroidManifest.xml
  32. 43 0
      shortcut_lib/src/main/java/com/xys/badge_lib/AppInfoUtil.java
  33. 721 0
      shortcut_lib/src/main/java/com/xys/badge_lib/AppShortCutUtil.java
  34. 180 0
      shortcut_lib/src/main/java/com/xys/badge_lib/BadgeUtil.java
  35. 42 0
      shortcut_lib/src/main/java/com/xys/shortcut_lib/FlowEntranceUtil.java
  36. 93 0
      shortcut_lib/src/main/java/com/xys/shortcut_lib/LauncherUtil.java
  37. 246 0
      shortcut_lib/src/main/java/com/xys/shortcut_lib/ShortcutSuperUtils.java
  38. 61 0
      shortcut_lib/src/main/java/com/xys/shortcut_lib/ShortcutUtils.java
  39. 15 0
      shortcut_lib/src/test/java/com/xys/shortcut_lib/ExampleUnitTest.java

+ 1 - 0
.idea/gradle.xml

@@ -14,6 +14,7 @@
             <option value="$PROJECT_DIR$/media/app" />
             <option value="$PROJECT_DIR$/media/cge_library" />
             <option value="$PROJECT_DIR$/media/share_library" />
+            <option value="$PROJECT_DIR$/shortcut_lib" />
             <option value="$PROJECT_DIR$/skin-support" />
             <option value="$PROJECT_DIR$/skin_christmas" />
             <option value="$PROJECT_DIR$/skin_newYear" />

+ 2 - 0
app/build.gradle

@@ -487,6 +487,8 @@ dependencies {
 
     // skin-support-constraint-layout ConstraintLayout 控件支持[可选]
     implementation 'com.r0adkll:slidableactivity:2.0.6'
+
+    implementation project(':shortcut_lib')
 }
 
 static def releaseTime() {

+ 8 - 0
app/src/main/AndroidManifest.xml

@@ -423,6 +423,14 @@
             android:screenOrientation="portrait"
             android:theme="@style/AppActionTheme" />
         <activity
+            android:name="com.sheep.gamegroup.view.activity.YFActWebX5"
+            android:screenOrientation="portrait"
+            android:theme="@style/AppActionTheme" >
+            <intent-filter>
+                <action android:name="android.intent.action.CREATE_SHORTCUT" />
+            </intent-filter>
+        </activity>
+        <activity
             android:name="com.sheep.gamegroup.view.activity.ActImg"
             android:screenOrientation="portrait"
             android:theme="@style/AppActionTheme" />

+ 5 - 0
app/src/main/java/com/sheep/gamegroup/model/api/ApiService.java

@@ -1026,6 +1026,11 @@ public interface ApiService {
      */
     @PUT("app/gift_bag/receive/{id}")
     Observable<BaseMessage> receiveGiftBag(@Path("id") int id);
+    /**
+     * 礼包中心-分类标签列表
+     */
+    @GET("app/gift_bag/tag")
+    Observable<BaseMessage> getGiftBagTag();
 
     /**
      * 获取热门福利

+ 0 - 1
app/src/main/java/com/sheep/gamegroup/module/game/fragment/FgtGameCenter.java

@@ -13,7 +13,6 @@ import com.sheep.gamegroup.util.KeyEventUtil;
 import com.sheep.gamegroup.util.ViewUtil;
 import com.sheep.gamegroup.view.activity.ActMain;
 import com.sheep.gamegroup.view.adapter.TitleFragmentListAdapter;
-import com.sheep.gamegroup.view.fragment.FgtGiftCenter;
 import com.sheep.jiuyan.samllsheep.R;
 import com.sheep.jiuyan.samllsheep.base.BaseFragment;
 import com.sheep.jiuyan.samllsheep.utils.G;

+ 66 - 0
app/src/main/java/com/sheep/gamegroup/module/game/fragment/FgtGiftCenter.java

@@ -0,0 +1,66 @@
+package com.sheep.gamegroup.module.game.fragment;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.widget.EditText;
+
+import com.sheep.gamegroup.model.entity.BaseMessage;
+import com.sheep.gamegroup.model.util.SheepSubscriber;
+import com.sheep.gamegroup.util.Jump2View;
+import com.sheep.jiuyan.samllsheep.R;
+import com.sheep.jiuyan.samllsheep.SheepApp;
+import com.sheep.jiuyan.samllsheep.base.BaseFragment;
+import com.sheep.jiuyan.samllsheep.utils.G;
+
+import butterknife.BindView;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * Created by realicing on 2019/3/13.
+ * realicing@sina.com
+ * 小绵羊3.5.1新增 -- 游戏礼包改版
+ */
+public class FgtGiftCenter extends BaseFragment{
+
+    @BindView(R.id.fgt_gift_center_type_list)
+    RecyclerView fgt_gift_center_type_list;
+    @BindView(R.id.fgt_gift_center_x_list)
+    RecyclerView fgt_gift_center_x_list;
+    @BindView(R.id.fgt_gift_center_input_et)
+    EditText fgt_gift_center_input_et;
+    @Override
+    public int getLayoutId() {
+        return R.layout.fgt_gift_center;
+    }
+
+    @Override
+    public void onViewCreated() {
+        initView();
+        initData();
+    }
+
+    private void initData() {
+        SheepApp.getInstance().getNetComponent().getApiService().getGiftBagTag()
+                        .subscribeOn(Schedulers.io())
+                        .observeOn(AndroidSchedulers.mainThread())
+                        .subscribe(new SheepSubscriber<BaseMessage>(SheepApp.getInstance()) {
+                            @Override
+                            public void onNext(BaseMessage baseMessage) {
+
+                            }
+
+                            @Override
+                            public void onError(BaseMessage baseMessage) {
+                                G.showToast(baseMessage);
+                            }
+                        });
+
+    }
+
+    public void initView() {
+        View wc_all_gift = findViewById(R.id.wc_all_gift);
+        wc_all_gift.setOnClickListener(view -> Jump2View.getInstance().goMyWelfare(getActivity()));
+    }
+
+}

+ 11 - 1
app/src/main/java/com/sheep/gamegroup/util/CommonUtil.java

@@ -63,10 +63,10 @@ import com.sheep.gamegroup.model.entity.WithdrawalEty;
 import com.sheep.gamegroup.model.entity.XiaomiGameEntity;
 import com.sheep.gamegroup.model.util.EntityUtils;
 import com.sheep.gamegroup.model.util.SheepSubscriber;
-import com.sheep.gamegroup.module.pay.activity.SheepWXPayEntryActivity;
 import com.sheep.gamegroup.usage.AppUsageManager;
 import com.sheep.gamegroup.view.activity.ActMain;
 import com.sheep.gamegroup.view.activity.GameTaskOrderListAct;
+import com.sheep.gamegroup.view.activity.YFActWebX5;
 import com.sheep.gamegroup.view.dialog.DialogNewbieTaskList;
 import com.sheep.jiuyan.samllsheep.BuildConfig;
 import com.sheep.jiuyan.samllsheep.Config;
@@ -2727,4 +2727,14 @@ public class CommonUtil {
         }
         return false;
     }
+
+    //添加有范商城桌面快捷入口
+    public void addYouFanLauncher() {
+
+    }
+
+    //已经添加有范商城快捷入口
+    public boolean hasYouFanLauncher() {
+        return DataUtil.getAsBoolean(YFActWebX5.KEY_HAS_YOU_FAN_LAUNCHER, false);
+    }
 }

+ 11 - 1
app/src/main/java/com/sheep/gamegroup/util/Jump2View.java

@@ -2738,6 +2738,9 @@ public class Jump2View {
         return true;
     }
 
+
+    //忽略 添加有范商城快捷入口
+    public static final String KEY_IGNORE_ADD_YOU_FAN_LAUNCHER = "ignore_add_you_fan_launcher";
     /**
      * 小绵羊3.4.7新增 -- 跳转商城优惠购物界面
      *
@@ -2745,9 +2748,16 @@ public class Jump2View {
      */
     public void gotoYfShop(Activity activity) {
         CommonUtil.getInstance().initUrlConfigByNet(Config.KEY_YF_SHOP_URL, url -> {
+            boolean isIgnore = DataUtil.getAsBoolean(KEY_IGNORE_ADD_YOU_FAN_LAUNCHER, false);
+            if(!isIgnore && !CommonUtil.getInstance().hasYouFanLauncher()) {//未忽略并且没有添加有范商品入口
+                ActionUtil.getInstance().addNextAction(ActWebX5.class.getSimpleName(), new DialogConfig().setTitle("温馨提示")
+                        .setMsg("亲,喜欢的话,就添加一个商城的桌面快捷入口吧!")
+                        .setBtnLeftText("否").setBtnLeftOnClickListener(view -> DataUtil.putAsBoolean(KEY_IGNORE_ADD_YOU_FAN_LAUNCHER, true))
+                        .setBtnRightText("是").setBtnRightOnClickListener(view -> CommonUtil.getInstance().addYouFanLauncher()));
+            }
             if (TextUtils.isEmpty(url))
                 url = SheepApp.getInstance().getConnectAddress().getYfShotHomeSheep();
-            goWeb(activity, new WebParams(url, Config.YF_SHOP_NAME).setShowTitle(false).tokenFirstUpperCase());
+            goWeb(activity, new WebParams(url, Config.YF_SHOP_NAME).tokenFirstUpperCase());
         });
     }
 

+ 134 - 0
app/src/main/java/com/sheep/gamegroup/util/SysAppUtil.java

@@ -2,15 +2,24 @@ package com.sheep.gamegroup.util;
 
 import android.app.Activity;
 import android.app.Dialog;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.graphics.BitmapFactory;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
 import android.os.Build;
 import android.provider.AlarmClock;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.text.format.Formatter;
 import android.view.Gravity;
@@ -26,6 +35,9 @@ import com.sheep.gamegroup.model.entity.BaseMessage;
 import com.sheep.gamegroup.model.entity.DialogConfig;
 import com.sheep.gamegroup.model.entity.Version;
 import com.sheep.gamegroup.model.util.SheepSubscriber;
+import com.sheep.gamegroup.view.activity.YFActWebX5;
+import com.sheep.jiuyan.samllsheep.BuildConfig;
+import com.sheep.jiuyan.samllsheep.Config;
 import com.sheep.jiuyan.samllsheep.R;
 import com.sheep.jiuyan.samllsheep.SheepApp;
 import com.sheep.jiuyan.samllsheep.utils.ClassFileHelper;
@@ -33,6 +45,8 @@ import com.sheep.jiuyan.samllsheep.utils.G;
 import com.sheep.jiuyan.samllsheep.utils.SpUtils;
 import com.tencent.bugly.beta.Beta;
 import com.tencent.bugly.beta.UpgradeInfo;
+import com.xys.shortcut_lib.ShortcutSuperUtils;
+import com.xys.shortcut_lib.ShortcutUtils;
 import com.zhy.http.okhttp.OkHttpUtils;
 import com.zhy.http.okhttp.callback.FileCallBack;
 
@@ -50,6 +64,7 @@ import java.util.Calendar;
 import java.util.List;
 import java.util.Locale;
 
+import androidx.annotation.RequiresApi;
 import io.reactivex.Observable;
 import io.reactivex.android.schedulers.AndroidSchedulers;
 import io.reactivex.functions.Function;
@@ -774,4 +789,123 @@ public class SysAppUtil {
     public static String getDeviceMac(){
         return MacDeviceUtil.getMac(SheepApp.getInstance());
     }
+
+
+
+    /**
+     * 启动应用的设置
+     */
+    public static void startAppSettings(Activity activity) {
+        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+        intent.setData(Uri.parse("package:" + BuildConfig.APPLICATION_ID));
+        activity.startActivity(intent);
+    }
+
+
+
+    //添加有范商城快捷入口
+    public static void addShortcutTest(Activity activity) {
+        if(Build.VERSION.SDK_INT >=  Build.VERSION_CODES.O){
+            SysAppUtil.addShortcutTest8(activity);
+        } else if(Build.VERSION.SDK_INT >=  Build.VERSION_CODES.N_MR1){
+            SysAppUtil.addShortcutTest7(activity);
+        } else {
+            SysAppUtil.addShortcutTest6(activity);
+        }
+    }
+
+
+
+    @android.support.annotation.RequiresApi(api = Build.VERSION_CODES.O)
+    public static void addShortcutTest8(Activity activity) {
+        String mShortcutName = Config.YF_SHOP_NAME;
+        ShortcutManager shortcutManager = (ShortcutManager) activity.getSystemService(Context.SHORTCUT_SERVICE);
+        boolean requestPinShortcutSupported = shortcutManager.isRequestPinShortcutSupported();
+        LogUtil.println("addShortcutTest8", "启动器是否支持固定快捷方式: "+requestPinShortcutSupported);
+
+        if (requestPinShortcutSupported) {
+
+            Intent shortcutInfoIntent = new Intent(activity, yfCls);
+
+            shortcutInfoIntent.setAction(Intent.ACTION_VIEW);
+
+            ShortcutInfo info = new ShortcutInfo.Builder(activity, String.valueOf(mShortcutName.hashCode()))
+                    .setIcon(Icon.createWithResource(activity, R.drawable.icon_yf))
+                    .setShortLabel(mShortcutName.substring(0,2))
+                    .setLongLabel(mShortcutName)
+                    .setIntent(shortcutInfoIntent)
+                    .build();
+
+            //当添加快捷方式的确认弹框弹出来时,将被回调CallBackReceiver里面的onReceive方法
+            PendingIntent shortcutCallbackIntent = PendingIntent.getBroadcast(activity, 0, new Intent(activity, CallBackReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT);
+
+            shortcutManager.requestPinShortcut(info, shortcutCallbackIntent.getIntentSender());
+            showShortcutTip(activity);
+        } else {
+            G.showToast("暂不支持");
+        }
+    }
+
+    //展示提示框
+    private static void showShortcutTip(Activity activity) {
+        ViewUtil.showMsgDialog(activity, new DialogConfig().setTitle("已尝试添加有范商城到桌面").setMsg("若添加失败,请前往系统设置为小绵羊打开\"创建桌面快捷方式\"的权限")
+                .setBtnLeftText("取消").setBtnRightText("前往设置").setBtnRightOnClickListener(view -> startAppSettings(activity)));
+    }
+
+    class CallBackReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            LogUtil.println("addShortcutTest8", "onReceive: 固定快捷方式的回调");
+        }
+    }
+
+    @RequiresApi(api = Build.VERSION_CODES.N_MR1)
+    public static void addShortcutTest7(Activity activity) {
+        String mShortcutName = Config.YF_SHOP_NAME;
+        ShortcutManager systemService = activity.getSystemService(ShortcutManager.class);
+        //设置Intent跳转逻辑
+        Intent intent = new Intent(activity, yfCls);
+        intent.setAction(Intent.ACTION_VIEW);
+
+        //设置ID
+        ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(activity, String.valueOf(mShortcutName.hashCode()))
+                //设置短标题
+                .setShortLabel(mShortcutName.substring(0,2))
+                //设置长标题
+                .setLongLabel(mShortcutName)
+                //设置icon
+                .setIcon(Icon.createWithResource(activity, R.drawable.icon_yf))
+                //设置Intent
+                .setIntent(intent)
+                .build();
+        //这样就可以通过长按图标显示出快捷方式了
+        systemService.setDynamicShortcuts(ListUtil.asList(shortcutInfo));
+        showShortcutTip(activity);
+    }
+
+    public static void addShortcutTest6(Activity activity) {
+        String mShortcutName = Config.YF_SHOP_NAME;
+        // 系统方式创建
+        // ShortcutUtils.addShortcut(this, getShortCutIntent(), mShortcutName);
+
+        // 创建前判断是否存在
+        if (!ShortcutSuperUtils.isShortCutExist(activity, mShortcutName, getShortCutIntent(activity))) {
+            ShortcutUtils.addShortcut(activity, getShortCutIntent(activity), mShortcutName, false,
+                    BitmapFactory.decodeResource(activity.getResources(), R.drawable.icon_yf));
+            G.showToast("添加成功");
+        } else {
+            G.showToast("已经添加成功");
+        }
+
+        // 为某个包创建快捷方式
+        // ShortcutSuperUtils.addShortcutByPackageName(this, this.getPackageName());
+    }
+    public static final Class<? extends Activity> yfCls = YFActWebX5.class;
+    private static Intent getShortCutIntent(Activity activity) {
+        // 使用MAIN,可以避免部分手机(比如华为、HTC部分机型)删除应用时无法删除快捷方式的问题
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_DEFAULT);
+        intent.setClass(activity, yfCls);
+        return intent;
+    }
 }

+ 55 - 21
app/src/main/java/com/sheep/gamegroup/util/TestUtil.java

@@ -4,15 +4,20 @@ import android.app.Activity;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Paint;
+import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -25,6 +30,7 @@ import android.view.Gravity;
 import android.view.View;
 import android.widget.ArrayAdapter;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
@@ -55,6 +61,7 @@ import com.sheep.gamegroup.view.activity.ActMain;
 import com.sheep.gamegroup.view.activity.ActSheepApkList;
 import com.sheep.gamegroup.view.activity.ActSheepPngList;
 import com.sheep.gamegroup.view.activity.ActTestExpression;
+import com.sheep.gamegroup.view.activity.YFActWebX5;
 import com.sheep.gamegroup.view.activity.NotificationsUtils;
 import com.sheep.gamegroup.view.dialog.DialogGameOrTaskOrGift;
 import com.sheep.gamegroup.view.dialog.DialogLoading;
@@ -73,17 +80,21 @@ import com.umeng.socialize.ShareAction;
 import com.umeng.socialize.UMShareListener;
 import com.umeng.socialize.bean.SHARE_MEDIA;
 import com.umeng.socialize.media.UMImage;
+import com.xys.shortcut_lib.ShortcutSuperUtils;
+import com.xys.shortcut_lib.ShortcutUtils;
 import com.zhy.http.okhttp.OkHttpUtils;
 import com.zhy.http.okhttp.callback.FileCallBack;
 import com.zhy.http.okhttp.callback.StringCallback;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
+import androidx.annotation.RequiresApi;
 import cn.finalteam.rxgalleryfinal.bean.MediaBean;
 import cn.finalteam.rxgalleryfinal.utils.MediaUtils;
 import cn.jpush.android.api.JPushInterface;
@@ -264,9 +275,9 @@ public class TestUtil {
      */
     public static void test(final Activity activity) {
         final String[] items = {"复制token", "添加token", "复制打点数据", "从jenkins下载小绵羊安装包", "测试表情包",
-                "跳转QQ", "跳转QQ群", "测试设备信息","下载视频测试","爱奇艺VIP会员", "分享我的签名的小绵羊apk", "分享当前小绵羊apk",
-                "测试升级对话框","少数民族姓名", "开启皮肤", "不开启皮肤", "我的游戏", "优惠券弹窗", "填写收件地址弹窗",
-                "朗读文字", "游戏搜索", "测试插件","测试bitmap", "剪切视频", "我的关注", "足迹",
+                "跳转QQ", "跳转QQ群", "测试有范","测试有范6.0","测试有范7.0","测试有范8.0", "测试设备信息", "下载视频测试", "爱奇艺VIP会员", "分享我的签名的小绵羊apk", "分享当前小绵羊apk",
+                "测试升级对话框", "少数民族姓名", "开启皮肤", "不开启皮肤", "我的游戏", "优惠券弹窗", "填写收件地址弹窗",
+                "朗读文字", "游戏搜索", "测试插件", "测试bitmap", "剪切视频", "我的关注", "足迹",
                 "测试联通卡", "测试联通卡2", "测试签名1", "测试签名2", "测试孔剑秋faq正式服",
                 "跳转QQ1", "跳转QQ2", "跳转白白QQ", "龙猫竞猜", "龙猫竞猜-scheme",
                 "有米科技", "手机型号测试", "测试通知栏", "测试自定义通知栏", "测试自定义通知栏2",
@@ -285,16 +296,36 @@ public class TestUtil {
     }
 
     public static void testFunction(Activity activity, String item) {
-        if(activity == null){
+        if (activity == null) {
             return;
         }
         switch (item) {
+            case "测试有范":
+                SysAppUtil.addShortcutTest(activity);
+                break;
+            case "测试有范6.0":
+                SysAppUtil.addShortcutTest6(activity);
+                break;
+            case "测试有范7.0":
+                if(Build.VERSION.SDK_INT >=  Build.VERSION_CODES.N_MR1) {
+                    SysAppUtil.addShortcutTest7(activity);
+                } else {
+                    G.showToast("不支持7.0");
+                }
+                break;
+            case "测试有范8.0":
+                if(Build.VERSION.SDK_INT >=  Build.VERSION_CODES.O) {
+                    SysAppUtil.addShortcutTest8(activity);
+                } else {
+                    G.showToast("不支持8.0");
+                }
+                break;
             case "测试设备信息":
                 testDeviceInfo();
                 break;
             case "下载视频测试":
                 String downloadUrl = "http://cdn.video.17xmy.com/ljok9RZZvXc5qwvoCxEGudchO6Ti";
-                String fileName = System.currentTimeMillis()+".mp4";
+                String fileName = System.currentTimeMillis() + ".mp4";
                 Jump2View.getInstance().startDownloadService(downloadUrl, new File(DIR, fileName).getAbsolutePath());
 //                OkHttpUtils.get().url(downloadUrl).build().execute(new FileCallBack(DIR, fileName) {
 //                    @Override
@@ -590,18 +621,18 @@ public class TestUtil {
                 break;
             case "添加token":
                 CharSequence text = StringUtils.getCopyText();
-                if(text != null) {
+                if (text != null) {
                     String msg = text.toString();
-                    if(msg.contains("@")) {
+                    if (msg.contains("@")) {
                         SpUtils.saveToken(activity, text.toString());
                         addUser(text.toString());
-                    } else if(msg.toLowerCase().startsWith("qqq")){
+                    } else if (msg.toLowerCase().startsWith("qqq")) {
                         String qqq = StringUtils.filterUnNumber(msg);
                         ViewUtil.showMsgDialog(activity, new DialogConfig().setMsg("跳转提示").setMsg("是否跳转QQ群:" + qqq + "\n点击【保存】按钮,可以通过测试功能中的【复制token】复制token并跳转到该QQ群")
                                 .setMsgGravity(Gravity.START)
                                 .setBtnRightText("跳转").setBtnRightOnClickListener(view -> QQUtil.skip3(activity, qqq))
                                 .setBtnLeftText("保存QQ群").setBtnLeftOnClickListener(view -> DataUtil.putAsString("testQQQ", qqq)));
-                    } else if(msg.toLowerCase().startsWith("qq")){
+                    } else if (msg.toLowerCase().startsWith("qq")) {
                         String qq = StringUtils.filterUnNumber(msg);
                         ViewUtil.showMsgDialog(activity, new DialogConfig().setMsg("跳转提示").setMsg("是否跳转QQ:" + qq + "\n点击【保存】按钮,可以通过测试功能中的【复制token】复制token并跳转到该QQ")
                                 .setMsgGravity(Gravity.START)
@@ -613,11 +644,11 @@ public class TestUtil {
             case "复制token":
                 StringUtils.CopyText(SpUtils.getToken(activity));
                 String qq = DataUtil.getAsString("testQQ", null);
-                if(!TextUtils.isEmpty(qq)){
+                if (!TextUtils.isEmpty(qq)) {
                     QQUtil.skip3(activity, qq);
                 }
                 String qqq = DataUtil.getAsString("testQQQ", null);
-                if(!TextUtils.isEmpty(qqq)){
+                if (!TextUtils.isEmpty(qqq)) {
                     QQUtil.skip3(activity, qqq);
                 }
                 break;
@@ -697,6 +728,7 @@ public class TestUtil {
         }
     }
 
+
     /**
      * 测试设备信息
      */
@@ -727,7 +759,7 @@ public class TestUtil {
     }
 
     private static void testReadText(String msg, float pitch) {
-       TextToSpeechUtil.get().speakMsg(msg, pitch);
+        TextToSpeechUtil.get().speakMsg(msg, pitch);
     }
 
     //测试插件
@@ -735,7 +767,7 @@ public class TestUtil {
         SheepPluginUtil.checkAndRunPlugin(activity, Plugin.media)
                 .subscribeOn(Schedulers.io())
                 .observeOn(AndroidSchedulers.mainThread())
-                .subscribe(new AbsObserver<Plugin>(){
+                .subscribe(new AbsObserver<Plugin>() {
                     @Override
                     public void onNext(Plugin plugin) {
                         CallBackAPI.get().goAct(activity, "MainActivity");
@@ -832,7 +864,7 @@ public class TestUtil {
     }
 
     public static void testArticleVideo(View itemView, List<DiscoveryVideo> videoList, DiscoveryVideo item) {
-        if(isTest()){
+        if (isTest()) {
             itemView.setOnLongClickListener(new View.OnLongClickListener() {
                 @Override
                 public boolean onLongClick(View view) {
@@ -848,7 +880,7 @@ public class TestUtil {
                                 @Override
                                 public void onClick(DialogInterface dialogInterface, int which) {
                                     String chooseAction = list.get(which);
-                                    switch (chooseAction){
+                                    switch (chooseAction) {
                                         case "封面90":
                                             resetArticleVideoCover(item, 90);
                                             break;
@@ -872,21 +904,21 @@ public class TestUtil {
     }
 
     private static void resetArticleVideoCover(DiscoveryVideo item, int rotate) {
-        item.setCover(item.getResource()+"?vframe/jpg/offset/0/rotate/"+rotate);
+        item.setCover(item.getResource() + "?vframe/jpg/offset/0/rotate/" + rotate);
         resetArticleVideo(item);
     }
 
     //自动修复所有视频的时长
     private static void resetArticleVideoDuration(List<DiscoveryVideo> videoList) {
         for (DiscoveryVideo video : videoList) {
-            if(video.getDuration() < 1 || video.getDuration() > 15)//时长小于1,大于15代表错误
+            if (video.getDuration() < 1 || video.getDuration() > 15)//时长小于1,大于15代表错误
                 resetArticleVideoDuration(video);
         }
     }
 
     //自动修复单个视频的时长
     private static void resetArticleVideoDuration(DiscoveryVideo item) {
-        OkHttpUtils.get().url(item.getResource()+"?avinfo")
+        OkHttpUtils.get().url(item.getResource() + "?avinfo")
                 .build().execute(new StringCallback() {
             @Override
             public void onError(Call call, Exception e, int id) {
@@ -898,12 +930,13 @@ public class TestUtil {
                 JSONObject result = JSON.parseObject(response);
                 JSONObject format = result.getJSONObject("format");
                 item.setDuration(Float.valueOf(format.getString("duration")).intValue());
-                item.setCover(item.getResource()+"?vframe/png/offset/0");
+                item.setCover(item.getResource() + "?vframe/png/offset/0");
                 resetArticleVideo(item);
             }
         });
     }
-    private static void resetArticleVideo(DiscoveryVideo item){
+
+    private static void resetArticleVideo(DiscoveryVideo item) {
         JSONObject jsonObject = new JSONObject();
         jsonObject.put("id", item.getId());
         jsonObject.put("duration", item.getDuration());
@@ -1025,11 +1058,12 @@ public class TestUtil {
         }
         OkHttpUtils.get().url(url).build().execute(new FileCallBack(DIR, name) {
             private long time;
+
             @Override
             public void inProgress(float progress, long total, int id) {
                 if (action1 == null) {
                     long newTime = System.currentTimeMillis();
-                    if(time == 0 || newTime - time > 1000) {
+                    if (time == 0 || newTime - time > 1000) {
                         time = newTime;
 //                        G.showToast(String.format(Locale.CHINA, "%d%%", Math.round(progress * 100)));
                     }

+ 7 - 3
app/src/main/java/com/sheep/gamegroup/view/activity/ActWebX5.java

@@ -73,7 +73,7 @@ public class ActWebX5 extends BaseActWeb {
     ProgressBar act_web_loading_pb;
     @BindView(R.id.act_web_loading_iv)
     ImageView act_web_loading_iv;
-    private WebParams webParams;
+    protected WebParams webParams;
 
     @Override
     protected int getLayoutId() {
@@ -85,8 +85,7 @@ public class ActWebX5 extends BaseActWeb {
     public void initView() {
         ViewUtil.setImage(act_web_loading_iv, R.drawable.gif_sheep_loading);
 
-        Intent intent = getIntent();
-        webParams = (WebParams) intent.getSerializableExtra(WebParams.class.getSimpleName());
+        initWebParams();
         String url = webParams.getUrl();
         String jsUrl = webParams.getJsUrl();
         if (!TextUtils.isEmpty(url)) {
@@ -117,6 +116,11 @@ public class ActWebX5 extends BaseActWeb {
         }
     }
 
+    public void initWebParams() {
+        Intent intent = getIntent();
+        webParams = (WebParams) intent.getSerializableExtra(WebParams.class.getSimpleName());
+    }
+
     //初始化js代码数据
     private void initJsData(final String url, String jsUrl) {
         OkHttpUtils.get()

+ 23 - 0
app/src/main/java/com/sheep/gamegroup/view/activity/YFActWebX5.java

@@ -0,0 +1,23 @@
+package com.sheep.gamegroup.view.activity;
+
+
+import com.sheep.gamegroup.model.entity.WebParams;
+import com.sheep.gamegroup.util.DataUtil;
+import com.sheep.jiuyan.samllsheep.Config;
+import com.sheep.jiuyan.samllsheep.SheepApp;
+
+/**
+ * Created by realicing on 2019/3/20.
+ * realicing@sina.com
+ * 有范商城h5
+ */
+public class YFActWebX5 extends ActWebX5 {
+    public static final String KEY_HAS_YOU_FAN_LAUNCHER = "has_you_fan_launcher";
+    @Override
+    public void initWebParams() {
+        DataUtil.putAsBoolean(YFActWebX5.KEY_HAS_YOU_FAN_LAUNCHER, true);
+
+        String url = SheepApp.getInstance().getConnectAddress().getYfShotHomeSheep();
+        webParams = new WebParams(url, Config.YF_SHOP_NAME).tokenFirstUpperCase();
+    }
+}

BIN
app/src/main/res/drawable-xxhdpi/icon_yf.png


BIN
app/src/main/res/drawable/icon_yf_small.png


+ 69 - 0
app/src/main/res/layout/fgt_gift_center.xml

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.scwang.smartrefresh.layout.SmartRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/refresh"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <android.support.v4.widget.NestedScrollView
+        android:id="@+id/scrollView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scrollbars="none">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:focusable="true"
+            android:focusableInTouchMode="true"
+            android:orientation="vertical">
+
+            <RelativeLayout
+                android:id="@+id/wc_gift_center_title_container"
+                style="@style/style_wc_rl">
+
+                <TextView
+                    style="@style/style_wc_line_title"
+                    android:text="礼包中心" />
+
+                <TextView
+                    android:id="@+id/wc_all_gift"
+                    style="@style/style_wc_more"
+                    android:text="我的礼包" />
+            </RelativeLayout>
+
+            <android.support.v7.widget.AppCompatAutoCompleteTextView
+                android:id="@+id/fgt_gift_center_input_et"
+                android:layout_width="match_parent"
+                android:layout_height="30dp"
+                android:layout_marginStart="16dp"
+                android:layout_marginTop="21dp"
+                android:layout_marginEnd="16dp"
+                android:background="@drawable/shape_f5_solid_rectangle_15"
+                android:drawableStart="@mipmap/sous"
+                android:drawablePadding="6dp"
+                android:gravity="center|start"
+                android:hint="搜索游戏"
+                android:imeOptions="actionSearch"
+                android:maxLength="40"
+                android:paddingStart="6dp"
+                android:paddingEnd="6dp"
+                android:singleLine="true"
+                android:textColor="@color/black_6_3"
+                android:textColorHint="#CCCCCC"
+                android:textSize="12sp" />
+
+            <android.support.v7.widget.RecyclerView
+                android:id="@+id/fgt_gift_center_type_list"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+
+            <android.support.v7.widget.RecyclerView
+                android:id="@+id/fgt_gift_center_x_list"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+
+        </LinearLayout>
+
+    </android.support.v4.widget.NestedScrollView>
+
+</com.scwang.smartrefresh.layout.SmartRefreshLayout>

BIN
app/src/main/res/mipmap-xxhdpi/haohualb.png


BIN
app/src/main/res/mipmap-xxhdpi/haohualb_c.png


BIN
app/src/main/res/mipmap-xxhdpi/icon_yf.png


BIN
app/src/main/res/mipmap-xxhdpi/libaotj.png


BIN
app/src/main/res/mipmap-xxhdpi/libaotj_c.png


BIN
app/src/main/res/mipmap-xxhdpi/remenlb.png


BIN
app/src/main/res/mipmap-xxhdpi/remenlb_c.png


BIN
app/src/main/res/mipmap-xxhdpi/sous.png


BIN
app/src/main/res/mipmap-xxhdpi/xinshoulb.png


BIN
app/src/main/res/mipmap-xxhdpi/xinshoulb_c.png


+ 1 - 1
settings.gradle

@@ -1,4 +1,4 @@
-include ':app', ':view', ':ucrop', ':WaterWaveProgress', ':media', ':share_library', ':joevideolib', ':cge_library', ':skin-support', ':skin_christmas', ':skin_newYear'//, ':RxGalleryFinal', ':Aria', ':datashare', ':AriaAnnotations'
+include ':app', ':view', ':ucrop', ':WaterWaveProgress', ':media', ':share_library', ':joevideolib', ':cge_library', ':skin-support', ':skin_christmas', ':skin_newYear', ':shortcut_lib'//, ':RxGalleryFinal', ':Aria', ':datashare', ':AriaAnnotations'
 
 project(':media').projectDir = new File('media/app')
 project(':share_library').projectDir = new File('media/share_library')

+ 1 - 0
shortcut_lib/.gitignore

@@ -0,0 +1 @@
+/build

+ 24 - 0
shortcut_lib/build.gradle

@@ -0,0 +1,24 @@
+apply plugin: 'com.android.library'
+
+android {
+    compileSdkVersion 28
+
+    defaultConfig {
+        minSdkVersion 14
+        targetSdkVersion 27
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    testImplementation 'junit:junit:4.12'
+    implementation 'com.android.support:appcompat-v7:28.0.0'
+}

+ 17 - 0
shortcut_lib/proguard-rules.pro

@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/xuyisheng/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}

+ 13 - 0
shortcut_lib/src/androidTest/java/com/xys/shortcut_lib/ApplicationTest.java

@@ -0,0 +1,13 @@
+package com.xys.shortcut_lib;
+
+import android.app.Application;
+import android.test.ApplicationTestCase;
+
+/**
+ * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
+ */
+public class ApplicationTest extends ApplicationTestCase<Application> {
+    public ApplicationTest() {
+        super(Application.class);
+    }
+}

+ 235 - 0
shortcut_lib/src/main/AndroidManifest.xml

@@ -0,0 +1,235 @@
+<manifest package="com.xys.shortcut_lib"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+
+    <uses-permission
+        android:name="android.permission.WRITE_SETTINGS"
+        tools:ignore="ProtectedPermissions" />
+
+    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
+    <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"/>
+
+    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS"/>
+
+    <uses-permission android:name="com.android.launcher2.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.android.launcher2.permission.WRITE_SETTINGS"/>
+
+    <uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS"/>
+
+    <uses-permission android:name="org.adw.launcher.permission.READ_SETTINGS"/>
+    <uses-permission android:name="org.adw.launcher.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="com.htc.launcher.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.htc.launcher.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="com.qihoo360.launcher.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.qihoo360.launcher.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="com.lge.launcher.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.lge.launcher.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="net.qihoo.launcher.permission.READ_SETTINGS"/>
+    <uses-permission android:name="net.qihoo.launcher.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="org.adwfreak.launcher.permission.READ_SETTINGS"/>
+    <uses-permission android:name="org.adwfreak.launcher.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="org.adw.launcher_donut.permission.READ_SETTINGS"/>
+    <uses-permission android:name="org.adw.launcher_donut.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="com.huawei.launcher3.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.huawei.launcher3.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="com.fede.launcher.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.fede.launcher.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="com.sec.android.app.twlauncher.settings.READ_SETTINGS"/>
+    <uses-permission android:name="com.sec.android.app.twlauncher.settings.WRITE_SETTINGS"/>
+    <uses-permission android:name="com.anddoes.launcher.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.anddoes.launcher.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="com.tencent.qqlauncher.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.tencent.qqlauncher.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="com.huawei.launcher2.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.huawei.launcher2.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="com.android.mylauncher.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.android.mylauncher.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="com.ebproductions.android.launcher.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.ebproductions.android.launcher.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="com.oppo.launcher.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.oppo.launcher.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="com.miui.mihome2.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.miui.mihome2.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="com.huawei.android.launcher.permission.READ_SETTINGS"/>
+    <uses-permission android:name="com.huawei.android.launcher.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="telecom.mdesk.permission.READ_SETTINGS"/>
+    <uses-permission android:name="telecom.mdesk.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="dianxin.permission.ACCESS_LAUNCHER_DATA"/>
+
+
+
+
+    <!--新添加-->
+    <uses-permission android:name="com.sonyericsson.home.permission.BROADCAST_BADGE" />
+    <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
+    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.htc.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.majeur.launcher.permission.UPDATE_BADGE" />
+    <uses-permission android:name="com.htc.launcher.permission.UPDATE_SHORTCUT" />
+    <uses-permission android:name="com.anddoes.launcher.permission.UPDATE_COUNT" />
+    <uses-permission android:name="com.aliyun.permission.STORAGE_SERVICE" />
+    <uses-permission android:name="nxp.permission.ACCESS_WALLET_SERVICE" />
+    <uses-permission android:name="com.samsung.android.authservice.permission.READ_CONTENT_PROVIDER" />
+    <uses-permission android:name="com.miui.mihome2.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.miui.mihome2.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.aliyun.homeshell.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.aliyun.homeshell.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.lenovo.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.lenovo.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.iLoong.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.iLoong.permission.READ_SETTINGS" />
+    <uses-permission android:name="cn.nubia.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="cn.nubia.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.smartisanos.launcher.WRITE_DATABASE" />
+    <uses-permission android:name="com.smartisanos.launcher.READ_DATABASE" />
+    <uses-permission android:name="com.smartisanos.launcher.data.ExportDataProvider" />
+    <uses-permission android:name="com.teslacoilsw.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.teslacoilsw.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.meizu.flyme.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.meizu.flyme.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.ztemt.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.ztemt.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.zte.lqsoft.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.zte.lqsoft.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.baoruan.launcher2.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.baoruan.launcher2.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.fineos.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.fineos.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.ibingo.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.ibingo.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.zui.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.zui.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.qihoo360.screenlock.permission.READ_LOCAL_THEME" />
+    <uses-permission android:name="com.qihoo360.screenlock.permission.WRITE_LOCAL_THEME" />
+    <uses-permission android:name="com.zte.mifavor.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.zte.mifavor.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.lo.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.lo.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.android.tpwlauncher2.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.android.tpwlauncher2.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.android.sprdlauncher1.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.android.sprdlauncher1.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.s.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.s.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.zte.mobile.ZteLauncher3D.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.zte.mobile.ZteLauncher3D.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.android.launcher23.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.android.launcher23.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.mgyun.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.mgyun.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.asus.launcher3.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.asus.launcher3.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.tsf.shell.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.tsf.shell.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.tul.aviate.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.tul.aviate.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.lenovo.launcherhdmarket.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.lenovo.launcherhdmarket.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.hola.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.hola.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.qihoo360.home.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.qihoo360.home.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.slim.slimlauncher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.slim.slimlauncher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.huaqin.launcherEx.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.huaqin.launcherEx.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.epic.launcher.tw.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.epic.launcher.tw.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.android.lewalauncher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.android.lewalauncher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.Dean.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.Dean.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="app.cobo.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="app.cobo.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.alphalp.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.alphalp.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.lollipop.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.lollipop.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.l.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.l.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.dlto.atom.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.dlto.atom.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.android.sprdlauncher2.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.android.sprdlauncher2.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.konka.launcher2.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.konka.launcher2.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.mycheering.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.mycheering.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.microsoft.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.microsoft.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.nicelauncher.lolauncher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.nicelauncher.lolauncher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.jui.launcher3.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.jui.launcher3.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.android.launcher2.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.android.launcher2.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.qihoo360.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.qihoo360.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.lge.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.lge.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="net.qihoo.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="net.qihoo.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="org.adw.launcher_donut.permission.READ_SETTINGS" />
+    <uses-permission android:name="org.adw.launcher_donut.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.huawei.launcher3.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.huawei.launcher3.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.sec.android.app.twlauncher.settings.READ_SETTINGS" />
+    <uses-permission android:name="com.sec.android.app.twlauncher.settings.WRITE_SETTINGS" />
+    <uses-permission android:name="com.anddoes.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.anddoes.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.tencent.qqlauncher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.tencent.qqlauncher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.huawei.launcher2.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.huawei.launcher2.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.ebproductions.android.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.ebproductions.android.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="telecom.mdesk.permission.READ_SETTINGS" />
+    <uses-permission android:name="telecom.mdesk.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="dianxin.permission.ACCESS_LAUNCHER_DATA" />
+    <uses-permission android:name="com.modaco.android.launchergb.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.modaco.android.launchergb.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.sec.android.app.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.sec.android.app.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.bbk.launcher2.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.bbk.launcher2.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.htc.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.sec.android.app.twlauncher.WRITE_SETTINGS" />
+    <uses-permission android:name="com.sec.android.app.twlauncher.READ_SETTINGS" />
+    <uses-permission android:name="org.adw.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="org.adw.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="org.adwfreak.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="org.adwfreak.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.gau.go.launcherex.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.gau.go.launcherex.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.fede.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.fede.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.oppo.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.oppo.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.nd.android.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.nd.android.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.android.mylauncher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.android.mylauncher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.huawei.android.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.huawei.android.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.huawei.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.huawei.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.mx.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.mx.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="com.google.android.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.google.android.launcher.permission.WRITE_SETTINGS" />
+    <!--新添加end-->
+    <application
+        android:allowBackup="true"
+        android:supportsRtl="true">
+
+    </application>
+
+</manifest>

+ 43 - 0
shortcut_lib/src/main/java/com/xys/badge_lib/AppInfoUtil.java

@@ -0,0 +1,43 @@
+package com.xys.badge_lib;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+
+public final class AppInfoUtil {
+
+    private AppInfoUtil() throws InstantiationException {
+        throw new InstantiationException("This class is not for instantiation");
+    }
+
+    /**
+     * Retrieve launcher activity name of the application from the context
+     *
+     * @param context The context of the application package.
+     * @return launcher activity name of this application. From the
+     * "android:name" attribute.
+     */
+    public static String getLauncherClassName(Context context) {
+        PackageManager packageManager = context.getPackageManager();
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        // To limit the components this Intent will resolve to, by setting an
+        // explicit package name.
+        intent.setPackage(context.getPackageName());
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        // All Application must have 1 Activity at least.
+        // Launcher activity must be found!
+        ResolveInfo info = packageManager
+                .resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        // get a ResolveInfo containing ACTION_MAIN, CATEGORY_LAUNCHER
+        // if there is no Activity which has filtered by CATEGORY_DEFAULT
+        if (info == null) {
+            info = packageManager.resolveActivity(intent, 0);
+        }
+        //////////////////////另一种实现方式//////////////////////
+        // ComponentName componentName = context.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName()).getComponent();
+        // return componentName.getClassName();
+        //////////////////////另一种实现方式//////////////////////
+        return info.activityInfo.name;
+    }
+}

+ 721 - 0
shortcut_lib/src/main/java/com/xys/badge_lib/AppShortCutUtil.java

@@ -0,0 +1,721 @@
+package com.xys.badge_lib;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Typeface;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.RoundRectShape;
+import android.net.Uri;
+import android.os.Build;
+import android.support.v4.content.res.ResourcesCompat;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.TypedValue;
+
+import java.util.List;
+
+/***
+ * 应用的快捷方式工具类
+ *
+ * @author yang
+ * @deprecated
+ */
+public class AppShortCutUtil {
+
+    private static final String TAG = "AppShortCutUtil";
+    //默认圆角半径
+    private static final int DEFAULT_CORNER_RADIUS_DIP = 8;
+    //默认边框宽度
+    private static final int DEFAULT_STROKE_WIDTH_DIP = 2;
+    //边框的颜色
+    private static final int DEFAULT_STROKE_COLOR = Color.WHITE;
+    //中间数字的颜色
+    private static final int DEFAULT_NUM_COLOR = Color.parseColor("#CCFF0000");
+
+    /***
+     * 生成有数字的图片(没有边框)
+     *
+     * @param context   context
+     * @param icon      图片
+     * @param isShowNum 是否要绘制数字
+     * @param num       数字字符串:整型数字 超过99,显示为"99+"
+     * @return 生成有数字的图片
+     */
+    public static Bitmap generatorNumIcon(Context context, Bitmap icon, boolean isShowNum, String num) {
+        DisplayMetrics dm = context.getResources().getDisplayMetrics();
+        //基准屏幕密度
+        float baseDensity = 1.5f;//240dpi
+        float factor = dm.density / baseDensity;
+        Log.e(TAG, "density:" + dm.density);
+        Log.e(TAG, "dpi:" + dm.densityDpi);
+        Log.e(TAG, "factor:" + factor);
+        // 初始化画布
+        int iconSize = (int) context.getResources().getDimension(android.R.dimen.app_icon_size);
+        Bitmap numIcon = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(numIcon);
+        // 拷贝图片
+        Paint iconPaint = new Paint();
+        iconPaint.setDither(true);// 防抖动
+        iconPaint.setFilterBitmap(true);// 用来对Bitmap进行滤波处理,这样,当你选择Drawable时,会有抗锯齿的效果
+        Rect src = new Rect(0, 0, icon.getWidth(), icon.getHeight());
+        Rect dst = new Rect(0, 0, iconSize, iconSize);
+        canvas.drawBitmap(icon, src, dst, iconPaint);
+        if (isShowNum) {
+            if (TextUtils.isEmpty(num)) {
+                num = "0";
+            }
+            if (!TextUtils.isDigitsOnly(num)) {
+                //非数字
+                Log.e(TAG, "the num is not digit :" + num);
+                num = "0";
+            }
+            int numInt = Integer.valueOf(num);
+            if (numInt > 99) {//超过99
+                num = "99+";
+                // 启用抗锯齿和使用设备的文本字体大小
+                Paint numPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
+                numPaint.setColor(Color.WHITE);
+                numPaint.setTextSize(20f * factor);
+                numPaint.setTypeface(Typeface.DEFAULT_BOLD);
+                int textWidth = (int) numPaint.measureText(num, 0, num.length());
+                Log.e(TAG, "text width:" + textWidth);
+                int circleCenter = (int) (15 * factor);//中心坐标
+                int circleRadius = (int) (13 * factor);//圆的半径
+                //绘制左边的圆形
+                Paint leftCirPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+                leftCirPaint.setColor(Color.RED);
+                canvas.drawCircle(iconSize - circleRadius - textWidth + (10 * factor), circleCenter, circleRadius, leftCirPaint);
+                //绘制右边的圆形
+                Paint rightCirPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+                rightCirPaint.setColor(Color.RED);
+                canvas.drawCircle(iconSize - circleRadius, circleCenter, circleRadius, rightCirPaint);
+                //绘制中间的距形
+                Paint rectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+                rectPaint.setColor(Color.RED);
+                RectF oval = new RectF(iconSize - circleRadius - textWidth + (10 * factor), 2 * factor, iconSize - circleRadius, circleRadius * 2 + 2 * factor);
+                canvas.drawRect(oval, rectPaint);
+                //绘制数字
+                canvas.drawText(num, (iconSize - textWidth / 2 - (24 * factor)), 23 * factor, numPaint);
+            } else {//<=99
+                // 启用抗锯齿和使用设备的文本字体大小
+                Paint numPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
+                numPaint.setColor(Color.WHITE);
+                numPaint.setTextSize(20f * factor);
+                numPaint.setTypeface(Typeface.DEFAULT_BOLD);
+                int textWidth = (int) numPaint.measureText(num, 0, num.length());
+                Log.e(TAG, "text width:" + textWidth);
+                //绘制外面的圆形
+                //Paint outCirPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+                //outCirPaint.setColor(Color.WHITE);
+                //canvas.drawCircle(iconSize - 15, 15, 15, outCirPaint);
+                //绘制内部的圆形
+                Paint inCirPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+                inCirPaint.setColor(Color.RED);
+                canvas.drawCircle(iconSize - 15 * factor, 15 * factor, 15 * factor, inCirPaint);
+                //绘制数字
+                canvas.drawText(num, (iconSize - textWidth / 2 - 15 * factor), 22 * factor, numPaint);
+            }
+        }
+        return numIcon;
+    }
+
+    /***
+     * 生成有数字的图片(没有边框)
+     *
+     * @param context   context
+     * @param icon      图片
+     * @param isShowNum 是否要绘制数字
+     * @param num       数字字符串:整型数字 超过99,显示为"99+"
+     * @return 生成有数字的图片
+     */
+    public static Bitmap generatorNumIcon2(Context context, Bitmap icon, boolean isShowNum, String num) {
+        DisplayMetrics dm = context.getResources().getDisplayMetrics();
+        //基准屏幕密度
+        float baseDensity = 1.5f;//240dpi
+        float factor = dm.density / baseDensity;
+        Log.e(TAG, "density:" + dm.density);
+        Log.e(TAG, "dpi:" + dm.densityDpi);
+        Log.e(TAG, "factor:" + factor);
+        // 初始化画布
+        int iconSize = (int) context.getResources().getDimension(android.R.dimen.app_icon_size);
+        Bitmap numIcon = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(numIcon);
+        // 拷贝图片
+        Paint iconPaint = new Paint();
+        iconPaint.setDither(true);// 防抖动
+        iconPaint.setFilterBitmap(true);// 用来对Bitmap进行滤波处理,这样,当你选择Drawable时,会有抗锯齿的效果
+        Rect src = new Rect(0, 0, icon.getWidth(), icon.getHeight());
+        Rect dst = new Rect(0, 0, iconSize, iconSize);
+        canvas.drawBitmap(icon, src, dst, iconPaint);
+        if (isShowNum) {
+            if (TextUtils.isEmpty(num)) {
+                num = "0";
+            }
+            if (!TextUtils.isDigitsOnly(num)) {
+                //非数字
+                Log.e(TAG, "the num is not digit :" + num);
+                num = "0";
+            }
+            int numInt = Integer.valueOf(num);
+            if (numInt > 99) {//超过99
+                num = "99+";
+            }
+            //启用抗锯齿和使用设备的文本字体大小
+            //测量文本占用的宽度
+            Paint numPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
+            numPaint.setColor(Color.WHITE);
+            numPaint.setTextSize(20f * factor);
+            numPaint.setTypeface(Typeface.DEFAULT_BOLD);
+            int textWidth = (int) numPaint.measureText(num, 0, num.length());
+            Log.e(TAG, "text width:" + textWidth);
+            /**----------------------------------*
+             * TODO 绘制圆角矩形背景 start
+             *------------------------------------*/
+            //圆角矩形背景的宽度
+            int backgroundHeight = (int) (2 * 15 * factor);
+            int backgroundWidth = textWidth > backgroundHeight ? (int) (textWidth + 10 * factor) : backgroundHeight;
+            canvas.save();//保存状态
+            ShapeDrawable drawable = getDefaultBackground(context);
+            drawable.setIntrinsicHeight(backgroundHeight);
+            drawable.setIntrinsicWidth(backgroundWidth);
+            drawable.setBounds(0, 0, backgroundWidth, backgroundHeight);
+            canvas.translate(iconSize - backgroundWidth, 0);
+            drawable.draw(canvas);
+            canvas.restore();//重置为之前保存的状态
+            /**----------------------------------*
+             * TODO 绘制圆角矩形背景 end
+             *------------------------------------*/
+            //绘制数字
+            canvas.drawText(num, (float) (iconSize - (backgroundWidth + textWidth) / 2), 22 * factor, numPaint);
+        }
+        return numIcon;
+    }
+
+    /***
+     * 生成有数字的图片(有边框)
+     *
+     * @param context   context
+     * @param icon      图片
+     * @param isShowNum 是否要绘制数字
+     * @param num       数字字符串:整型数字 超过99,显示为"99+"
+     * @return 生成有数字的图片
+     */
+    public static Bitmap generatorNumIcon3(Context context, Bitmap icon, boolean isShowNum, String num) {
+        DisplayMetrics dm = context.getResources().getDisplayMetrics();
+        //基准屏幕密度
+        float baseDensity = 1.5f;//240dpi
+        float factor = dm.density / baseDensity;
+        Log.e(TAG, "density:" + dm.density);
+        Log.e(TAG, "dpi:" + dm.densityDpi);
+        Log.e(TAG, "factor:" + factor);
+        // 初始化画布
+        int iconSize = (int) context.getResources().getDimension(android.R.dimen.app_icon_size);
+        Bitmap numIcon = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(numIcon);
+        // 拷贝图片
+        Paint iconPaint = new Paint();
+        iconPaint.setDither(true);// 防抖动
+        iconPaint.setFilterBitmap(true);// 用来对Bitmap进行滤波处理,这样,当你选择Drawable时,会有抗锯齿的效果
+        Rect src = new Rect(0, 0, icon.getWidth(), icon.getHeight());
+        Rect dst = new Rect(0, 0, iconSize, iconSize);
+        canvas.drawBitmap(icon, src, dst, iconPaint);
+        if (isShowNum) {
+            if (TextUtils.isEmpty(num)) {
+                num = "0";
+            }
+            if (!TextUtils.isDigitsOnly(num)) {
+                //非数字
+                Log.e(TAG, "the num is not digit :" + num);
+                num = "0";
+            }
+            int numInt = Integer.valueOf(num);
+            if (numInt > 99) {//超过99
+                num = "99+";
+            }
+            //启用抗锯齿和使用设备的文本字体大小
+            //测量文本占用的宽度
+            Paint numPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
+            numPaint.setColor(Color.WHITE);
+            numPaint.setTextSize(20f * factor);
+            numPaint.setTypeface(Typeface.DEFAULT_BOLD);
+            int textWidth = (int) numPaint.measureText(num, 0, num.length());
+            Log.e(TAG, "text width:" + textWidth);
+            /**----------------------------------*
+             * TODO 绘制圆角矩形背景:先画边框,再画内部的圆角矩形 start
+             *------------------------------------*/
+            //圆角矩形背景的宽度
+            int backgroundHeight = (int) (2 * 15 * factor);
+            int backgroundWidth = textWidth > backgroundHeight ? (int) (textWidth + 10 * factor) : backgroundHeight;
+            //边框的宽度
+            int strokeThickness = (int) (2 * factor);
+            canvas.save();//保存状态
+            int strokeHeight = backgroundHeight + strokeThickness * 2;
+            int strokeWidth = textWidth > strokeHeight ? (int) (textWidth + 10 * factor + 2 * strokeThickness) : strokeHeight;
+            ShapeDrawable outStroke = getDefaultStrokeDrawable(context);
+            outStroke.setIntrinsicHeight(strokeHeight);
+            outStroke.setIntrinsicWidth(strokeWidth);
+            outStroke.setBounds(0, 0, strokeWidth, strokeHeight);
+            canvas.translate(iconSize - strokeWidth - strokeThickness, strokeThickness);
+            outStroke.draw(canvas);
+            canvas.restore();//重置为之前保存的状态
+            canvas.save();//保存状态
+            ShapeDrawable drawable = getDefaultBackground(context);
+            drawable.setIntrinsicHeight((int) (backgroundHeight + 2 * factor));
+            drawable.setIntrinsicWidth((int) (backgroundWidth + 2 * factor));
+            drawable.setBounds(0, 0, backgroundWidth, backgroundHeight);
+            canvas.translate(iconSize - backgroundWidth - 2 * strokeThickness, 2 * strokeThickness);
+            drawable.draw(canvas);
+            canvas.restore();//重置为之前保存的状态
+            /**----------------------------------*
+             * TODO 绘制圆角矩形背景 end
+             *------------------------------------*/
+            //绘制数字
+            canvas.drawText(num, (float) (iconSize - (backgroundWidth + textWidth + 4 * strokeThickness) / 2), (22) * factor + 2 * strokeThickness, numPaint);
+        }
+        return numIcon;
+    }
+
+    /***
+     * 生成有数字的图片(有边框的)
+     *
+     * @param context   context
+     * @param icon      图片
+     * @param isShowNum 是否要绘制数字
+     * @param num       数字字符串:整型数字 超过99,显示为"99+"
+     * @return 生成有数字的图片
+     */
+    public static Bitmap generatorNumIcon4(Context context, Bitmap icon, boolean isShowNum, String num) {
+        DisplayMetrics dm = context.getResources().getDisplayMetrics();
+        //基准屏幕密度
+        float baseDensity = 1.5f;//240dpi
+        float factor = dm.density / baseDensity;
+        Log.e(TAG, "density:" + dm.density);
+        Log.e(TAG, "dpi:" + dm.densityDpi);
+        Log.e(TAG, "factor:" + factor);
+        // 初始化画布
+        int iconSize = (int) context.getResources().getDimension(android.R.dimen.app_icon_size);
+        Bitmap numIcon = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(numIcon);
+        // 拷贝图片
+        Paint iconPaint = new Paint();
+        iconPaint.setDither(true);// 防抖处理
+        iconPaint.setFilterBitmap(true);// 用来对Bitmap进行滤波处理,这样,当你选择Drawable时,会有抗锯齿的效果
+        Rect src = new Rect(0, 0, icon.getWidth(), icon.getHeight());
+        Rect dst = new Rect(0, 0, iconSize, iconSize);
+        canvas.drawBitmap(icon, src, dst, iconPaint);
+        if (isShowNum) {
+            if (TextUtils.isEmpty(num)) {
+                num = "0";
+            }
+            if (!TextUtils.isDigitsOnly(num)) {
+                //非数字
+                Log.e(TAG, "the num is not digit :" + num);
+                num = "0";
+            }
+            int numInt = Integer.valueOf(num);
+            if (numInt > 99) {//超过99
+                num = "99+";
+            }
+            //启用抗锯齿和使用设备的文本字体
+            //测量文本占用的宽度
+            Paint numPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
+            numPaint.setColor(Color.WHITE);
+            numPaint.setTextSize(25f * factor);
+            numPaint.setTypeface(Typeface.DEFAULT_BOLD);
+            int textWidth = (int) numPaint.measureText(num, 0, num.length());
+            Log.e(TAG, "text width:" + textWidth);
+            /**----------------------------------*
+             * TODO 绘制圆角矩形背景 start
+             *------------------------------------*/
+            //边框的宽度
+            int strokeThickness = (int) (DEFAULT_STROKE_WIDTH_DIP * factor);
+            //圆角矩形背景的宽度
+            float radiusPx = 15 * factor;
+            int backgroundHeight = (int) (2 * (radiusPx + strokeThickness));//2*(半径+边框宽度)
+            int backgroundWidth = textWidth > backgroundHeight ? (int) (textWidth + 10 * factor + 2 * strokeThickness) : backgroundHeight;
+            canvas.save();//保存状态
+            ShapeDrawable drawable = getDefaultBackground2(context);
+            drawable.setIntrinsicHeight(backgroundHeight);
+            drawable.setIntrinsicWidth(backgroundWidth);
+            drawable.setBounds(0, 0, backgroundWidth, backgroundHeight);
+            canvas.translate(iconSize - backgroundWidth - strokeThickness, 2 * strokeThickness);
+            drawable.draw(canvas);
+            canvas.restore();//重置为之前保存的状态
+            /**----------------------------------*
+             * TODO 绘制圆角矩形背景 end
+             *------------------------------------*/
+            //绘制数字
+            canvas.drawText(num, (float) (iconSize - (backgroundWidth + textWidth + 2 * strokeThickness) / 2), (float) (25 * factor + 2.5 * strokeThickness), numPaint);
+        }
+        return numIcon;
+    }
+
+    /***
+     * 创建原生系统的快捷方式
+     *
+     * @param context   context
+     * @param clazz     启动的activity
+     * @param nameResId 快捷方式名字的资源ID
+     * @param iconResId 图标的资源ID
+     * @param isShowNum 是否显示数字
+     * @param num       显示的数字:整型
+     * @param isStroke  是否加上边框
+     */
+    public static void installRawShortCut(Context context, Class<?> clazz, int nameResId,
+            int iconResId, boolean isShowNum, String num, boolean isStroke) {
+        String name = context.getString(nameResId);
+        Bitmap icon = BitmapFactory.decodeResource(context.getResources(), iconResId);
+        installRawShortCut(context, clazz, name, icon, isShowNum, num, isStroke);
+    }
+
+    /***
+     * 创建原生系统的快捷方式
+     *
+     * @param context   context
+     * @param clazz     启动的activity
+     * @param name      快捷方式的名字
+     * @param icon      图标
+     * @param isShowNum 是否显示数字
+     * @param num       显示的数字:整型
+     * @param isStroke  是否加上边框
+     */
+    public static void installRawShortCut(Context context, Class<?> clazz, String name,
+            Bitmap icon, boolean isShowNum, String num, boolean isStroke) {
+        Log.e(TAG, "installShortCut....");
+        Intent shortcutIntent = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
+        //名称
+        shortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
+        // 是否可以有多个快捷方式的副本,参数如果是true就可以生成多个快捷方式,如果是false就不会重复添加
+        shortcutIntent.putExtra("duplicate", false);
+        //点击快捷方式:打开activity
+        Intent mainIntent = new Intent(Intent.ACTION_MAIN);
+        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+        mainIntent.setClass(context, clazz);
+        shortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, mainIntent);
+        //快捷方式的图标
+        if (isStroke) {
+            shortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON,
+                    generatorNumIcon4(context, icon, isShowNum, num));
+        } else {
+            shortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON,
+                    generatorNumIcon2(context, icon, isShowNum, num));
+        }
+        context.sendBroadcast(shortcutIntent);
+    }
+
+
+    /***
+     * 是否已经创建了快捷方式
+     *
+     * @param context context
+     * @return 是否已经创建了快捷方式
+     */
+    public static boolean isAddShortCut(Context context, String name) {
+        Log.e(TAG, "isAddShortCut....");
+        boolean isInstallShortcut = false;
+        final ContentResolver cr = context.getContentResolver();
+        //TODO 注释的代码,在有的手机:修改了ROM的系统,不能支持
+            /*int versionLevel = android.os.Build.VERSION.SDK_INT;
+                        String AUTHORITY = "com.android.launcher2.settings";
+                        //2.2以上的系统的文件文件名字是不一样的
+                        if (versionLevel >= 8) {
+                            AUTHORITY = "com.android.launcher2.settings";
+                        } else {
+                            AUTHORITY = "com.android.launcher.settings";
+                        }*/
+
+        String AUTHORITY = getAuthorityFromPermission(context, "com.android.launcher.permission.READ_SETTINGS");
+        Log.e(TAG, "AUTHORITY  :  " + AUTHORITY);
+        final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+                + "/favorites?notify=true");
+        Cursor c = cr.query(CONTENT_URI,
+                new String[]{"title"}, "title=?",
+                new String[]{name}, null);
+        if (c != null && c.getCount() > 0) {
+            isInstallShortcut = true;
+        }
+        if (c != null) {
+            c.close();
+        }
+        Log.e(TAG, "isAddShortCut....isInstallShortcut=" + isInstallShortcut);
+        return isInstallShortcut;
+    }
+
+    /**
+     * 删除快捷方式
+     *
+     * @param context context
+     * @param clazz   clazz
+     */
+    public static void deleteShortCut(Context context, Class<?> clazz, String name) {
+        Log.e(TAG, "delShortcut....");
+        if (Build.MANUFACTURER.equalsIgnoreCase("Xiaomi")) {
+            //小米
+            //当为""时,不显示数字,相当于隐藏了)
+            xiaoMiShortCut(context, clazz, "");
+        } else if (Build.MANUFACTURER.equalsIgnoreCase("samsung")) {
+            //三星
+            samsungShortCut(context, "0");
+        } else {//其他原生系统手机
+            //删除显示数字的快捷方式
+            deleteRawShortCut(context, clazz, name);
+            //安装不显示数字的快捷方式
+            //installRawShortCut(context, clazz, false, "0");
+        }
+    }
+
+    /***
+     * 删除原生系统的快捷方式
+     *
+     * @param context context
+     * @param clazz   启动的activity
+     */
+    public static void deleteRawShortCut(Context context, Class<?> clazz, String name) {
+        Intent intent = new Intent("com.android.launcher.action.UNINSTALL_SHORTCUT");
+        //快捷方式的名称
+        intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
+        Intent intent2 = new Intent();
+        intent2.setClass(context, clazz);
+        intent2.setAction(Intent.ACTION_MAIN);
+        intent2.addCategory(Intent.CATEGORY_LAUNCHER);
+        intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent2);
+        context.sendBroadcast(intent);
+    }
+
+    /***
+     * 取得权限相应的认证URI
+     *
+     * @param context    context
+     * @param permission permission
+     * @return 取得权限相应的认证URI
+     */
+    public static String getAuthorityFromPermission(Context context, String permission) {
+        if (TextUtils.isEmpty(permission)) {
+            return null;
+        }
+        List<PackageInfo> packInfos = context.getPackageManager().getInstalledPackages(PackageManager.GET_PROVIDERS);
+        if (packInfos == null) {
+            return null;
+        }
+        for (PackageInfo info : packInfos) {
+            ProviderInfo[] providers = info.providers;
+            if (providers != null) {
+                for (ProviderInfo provider : providers) {
+                    if (permission.equals(provider.readPermission)
+                            || permission.equals(provider.writePermission)) {
+                        return provider.authority;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /***
+     * 在小米应用图标的快捷方式上加数字<br>
+     *
+     * @param context context
+     * @param num     显示的数字:大于99,为"99",当为""时,不显示数字,相当于隐藏了)<br><br>
+     *                <p/>
+     *                注意点:
+     *                context.getPackageName()+"/."+clazz.getSimpleName() (这个是启动activity的路径)中的"/."不能缺少
+     */
+    public static void xiaoMiShortCut(Context context, Class<?> clazz, String num) {
+        Log.e(TAG, "xiaoMiShortCut....");
+        Intent localIntent = new Intent("android.intent.action.APPLICATION_MESSAGE_UPDATE");
+        localIntent.putExtra("android.intent.extra.update_application_component_name", context.getPackageName() + "/." + clazz.getSimpleName());
+        if (TextUtils.isEmpty(num)) {
+            num = "";
+        } else {
+            int numInt = Integer.valueOf(num);
+            if (numInt > 0) {
+                if (numInt > 99) {
+                    num = "99";
+                }
+            } else {
+                num = "0";
+            }
+        }
+        localIntent.putExtra("android.intent.extra.update_application_message_text", num);
+        context.sendBroadcast(localIntent);
+    }
+
+    /***
+     * 索尼手机:应用图标的快捷方式上加数字
+     *
+     * @param context context
+     * @param num     num
+     */
+    public static void sonyShortCut(Context context, String num) {
+        String activityName = getLaunchActivityName(context);
+        if (activityName == null) {
+            return;
+        }
+        Intent localIntent = new Intent();
+        int numInt = Integer.valueOf(num);
+        boolean isShow = true;
+        if (numInt < 1) {
+            num = "";
+            isShow = false;
+        } else if (numInt > 99) {
+            num = "99";
+        }
+        localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", isShow);
+        localIntent.setAction("com.sonyericsson.home.action.UPDATE_BADGE");
+        localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME", activityName);
+        localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", num);
+        localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", context.getPackageName());
+        context.sendBroadcast(localIntent);
+    }
+
+    /***
+     * 三星手机:应用图标的快捷方式上加数字
+     *
+     * @param context context
+     * @param num     num
+     */
+    public static void samsungShortCut(Context context, String num) {
+        int numInt = Integer.valueOf(num);
+        if (numInt < 1) {
+            num = "0";
+        } else if (numInt > 99) {
+            num = "99";
+        }
+        String activityName = getLaunchActivityName(context);
+        Intent localIntent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
+        localIntent.putExtra("badge_count", num);
+        localIntent.putExtra("badge_count_package_name", context.getPackageName());
+        localIntent.putExtra("badge_count_class_name", activityName);
+        context.sendBroadcast(localIntent);
+    }
+
+    /***
+     * 在应用图标的快捷方式上加数字
+     *
+     * @param clazz     启动的activity
+     * @param isShowNum 是否显示数字
+     * @param num       显示的数字:整型
+     * @param isStroke  是否加上边框
+     */
+    public static void addNumShortCut(Context context, Class<?> clazz, boolean isShowNum, String num, boolean isStroke) {
+        Log.e(TAG, "manufacturer=" + Build.MANUFACTURER);
+        if (Build.MANUFACTURER.equalsIgnoreCase("Xiaomi")) {
+            //小米
+            xiaoMiShortCut(context, clazz, num);
+        } else if (Build.MANUFACTURER.equalsIgnoreCase("samsung")) {
+            //三星
+            samsungShortCut(context, num);
+        } else {//其他原生系统手机
+//            installRawShortCut(context, MainActivity.class, isShowNum, num, isStroke);
+        }
+    }
+
+    /***
+     * 取得当前应用的启动activity的名称:
+     * mainfest.xml中配置的 android:name:"
+     *
+     * @param context context
+     * @return 取得当前应用的启动activity的名称
+     */
+    public static String getLaunchActivityName(Context context) {
+        PackageManager localPackageManager = context.getPackageManager();
+        Intent localIntent = new Intent("android.intent.action.MAIN");
+        localIntent.addCategory("android.intent.category.LAUNCHER");
+        try {
+            for (ResolveInfo localResolveInfo : localPackageManager.queryIntentActivities(localIntent, 0)) {
+                if (!localResolveInfo.activityInfo.applicationInfo.packageName.equalsIgnoreCase(context.getPackageName()))
+                    continue;
+                return localResolveInfo.activityInfo.name;
+            }
+        } catch (Exception localException) {
+            return null;
+        }
+        return null;
+    }
+
+    /***
+     * 得到一个默认的背景:圆角矩形<br><br>
+     * 使用代码来生成一个背景:相当于用<shape>的xml的背景
+     *
+     * @return 得到一个默认的背景
+     */
+    private static ShapeDrawable getDefaultBackground(Context context) {
+        //这个是为了应对不同分辨率的手机,屏幕兼容性
+        int r = dipToPixels(context, DEFAULT_CORNER_RADIUS_DIP);
+        float[] outerR = new float[]{r, r, r, r, r, r, r, r};
+        //圆角矩形
+        RoundRectShape rr = new RoundRectShape(outerR, null, null);
+        ShapeDrawable drawable = new ShapeDrawable(rr);
+        drawable.getPaint().setColor(DEFAULT_NUM_COLOR);//设置颜色
+        return drawable;
+    }
+
+    /***
+     * 得到一个默认的背景:圆角矩形<br><br>
+     * 使用代码来生成一个背景:相当于用<shape>的xml的背景
+     *
+     * @return 得到一个默认的背景
+     */
+    private static ShapeDrawable getDefaultBackground2(Context context) {
+        //这个是为了应对不同分辨率的手机,屏幕兼容性
+        int r = dipToPixels(context, DEFAULT_CORNER_RADIUS_DIP);
+        float[] outerR = new float[]{r, r, r, r, r, r, r, r};
+        int distance = dipToPixels(context, DEFAULT_STROKE_WIDTH_DIP);
+        //圆角矩形
+        RoundRectShape rr = new RoundRectShape(outerR, null, null);
+        ShapeDrawable drawable = new ShapeDrawable(rr);
+//        drawable.getFillpaint().setColor(DEFAULT_NUM_COLOR);//设置填充颜色
+//        drawable.getStrokepaint().setColor(DEFAULT_STROKE_COLOR);//设置边框颜色
+//        drawable.getStrokepaint().setStrokeWidth(distance);//设置边框宽度
+        return drawable;
+    }
+
+
+    /***
+     * 得到一个默认的背景:圆角矩形<br><br>
+     * 使用代码来生成一个背景:相当于用<shape>的xml的背景
+     *
+     * @return 得到一个默认的背景
+     */
+    private static ShapeDrawable getDefaultStrokeDrawable(Context context) {
+        //这个是为了应对不同分辨率的手机,屏幕兼容性
+        int r = dipToPixels(context, DEFAULT_CORNER_RADIUS_DIP);
+        int distance = dipToPixels(context, DEFAULT_STROKE_WIDTH_DIP);
+        float[] outerR = new float[]{r, r, r, r, r, r, r, r};
+        //圆角矩形
+        RoundRectShape rr = new RoundRectShape(outerR, null, null);
+        ShapeDrawable drawable = new ShapeDrawable(rr);
+        drawable.getPaint().setStrokeWidth(distance);
+        drawable.getPaint().setStyle(Paint.Style.FILL);
+        drawable.getPaint().setColor(DEFAULT_STROKE_COLOR);//设置颜色
+        return drawable;
+    }
+
+    /***
+     * dp to px
+     *
+     * @param dip dip
+     * @return px
+     */
+    public static int dipToPixels(Context context, int dip) {
+        Resources r = context.getResources();
+        float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, r.getDisplayMetrics());
+        return (int) px;
+    }
+}

+ 180 - 0
shortcut_lib/src/main/java/com/xys/badge_lib/BadgeUtil.java

@@ -0,0 +1,180 @@
+package com.xys.badge_lib;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.ComponentName;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.support.v4.app.NotificationCompat;
+import android.util.Log;
+import android.widget.Toast;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public final class BadgeUtil {
+
+    private BadgeUtil() throws InstantiationException {
+        throw new InstantiationException("This class is not for instantiation");
+    }
+
+    /**
+     * 设置Badge 目前支持Launcher:
+     * <p/>
+     * MIUI
+     * Sony
+     * Samsung
+     * LG
+     * HTC
+     * Nova
+     *
+     * @param context context
+     * @param count   count
+     */
+    public static void setBadgeCount(Context context, int count, int iconResId) {
+        // TODO 生成器模式重构
+        if (count <= 0) {
+            count = 0;
+        } else {
+            count = Math.max(0, Math.min(count, 99));
+        }
+        if (Build.MANUFACTURER.equalsIgnoreCase("xiaomi")) {
+            setBadgeOfMIUI(context, count, iconResId);
+        } else if (Build.MANUFACTURER.equalsIgnoreCase("sony")) {
+            setBadgeOfSony(context, count);
+        } else if (Build.MANUFACTURER.toLowerCase().contains("samsung") ||
+                Build.MANUFACTURER.toLowerCase().contains("lg")) {
+            setBadgeOfSumsung(context, count);
+        } else if (Build.MANUFACTURER.toLowerCase().contains("htc")) {
+            setBadgeOfHTC(context, count);
+        } else if (Build.MANUFACTURER.toLowerCase().contains("nova")) {
+            setBadgeOfNova(context, count);
+        } else {
+            Toast.makeText(context, "Not Found Support Launcher", Toast.LENGTH_LONG).show();
+        }
+    }
+
+    /**
+     * 设置MIUI的Badge
+     *
+     * @param context context
+     * @param count   count
+     */
+    private static void setBadgeOfMIUI(Context context, int count, int iconResId) {
+        Log.d("xys", "Launcher : MIUI");
+        NotificationManager mNotificationManager = (NotificationManager) context
+                .getSystemService(Context.NOTIFICATION_SERVICE);
+        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, String.valueOf(iconResId));
+        builder.setContentTitle("title").setContentText("text").setSmallIcon(iconResId);
+        Notification notification = builder.build();
+        try {
+            Field field = notification.getClass().getDeclaredField("extraNotification");
+            Object extraNotification = field.get(notification);
+            Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class);
+            method.invoke(extraNotification, count);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        mNotificationManager.notify(0, notification);
+    }
+
+    /**
+     * 设置索尼的Badge
+     * <p/>
+     * 需添加权限:<uses-permission android:name="com.sonyericsson.home.permission.BROADCAST_BADGE" />
+     *
+     * @param context context
+     * @param count   count
+     */
+    private static void setBadgeOfSony(Context context, int count) {
+        String launcherClassName = com.xys.badge_lib.AppInfoUtil.getLauncherClassName(context);
+        if (launcherClassName == null) {
+            return;
+        }
+        boolean isShow = true;
+        if (count == 0) {
+            isShow = false;
+        }
+        Intent localIntent = new Intent();
+        localIntent.setAction("com.sonyericsson.home.action.UPDATE_BADGE");
+        localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", isShow);//是否显示
+        localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME", launcherClassName);//启动页
+        localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", String.valueOf(count));//数字
+        localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", context.getPackageName());//包名
+        context.sendBroadcast(localIntent);
+    }
+
+    /**
+     * 设置三星的Badge\设置LG的Badge
+     *
+     * @param context context
+     * @param count   count
+     */
+    private static void setBadgeOfSumsung(Context context, int count) {
+        // 获取你当前的应用
+        String launcherClassName = com.xys.badge_lib.AppInfoUtil.getLauncherClassName(context);
+        if (launcherClassName == null) {
+            return;
+        }
+        Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
+        intent.putExtra("badge_count", count);
+        intent.putExtra("badge_count_package_name", context.getPackageName());
+        intent.putExtra("badge_count_class_name", launcherClassName);
+        context.sendBroadcast(intent);
+    }
+
+    /**
+     * 设置HTC的Badge
+     *
+     * @param context context
+     * @param count   count
+     */
+    private static void setBadgeOfHTC(Context context, int count) {
+        Intent intentNotification = new Intent("com.htc.launcher.action.SET_NOTIFICATION");
+        ComponentName localComponentName = new ComponentName(context.getPackageName(),
+                com.xys.badge_lib.AppInfoUtil.getLauncherClassName(context));
+        intentNotification.putExtra("com.htc.launcher.extra.COMPONENT", localComponentName.flattenToShortString());
+        intentNotification.putExtra("com.htc.launcher.extra.COUNT", count);
+        context.sendBroadcast(intentNotification);
+
+        Intent intentShortcut = new Intent("com.htc.launcher.action.UPDATE_SHORTCUT");
+        intentShortcut.putExtra("packagename", context.getPackageName());
+        intentShortcut.putExtra("count", count);
+        context.sendBroadcast(intentShortcut);
+    }
+
+    /**
+     * 设置Nova的Badge
+     *
+     * @param context context
+     * @param count   count
+     */
+    private static void setBadgeOfNova(Context context, int count) {
+        ContentValues contentValues = new ContentValues();
+        contentValues.put("tag", context.getPackageName() + "/" +
+                com.xys.badge_lib.AppInfoUtil.getLauncherClassName(context));
+        contentValues.put("count", count);
+        context.getContentResolver().insert(Uri.parse("content://com.teslacoilsw.notifier/unread_count"),
+                contentValues);
+    }
+
+    public static void setBadgeOfMadMode(Context context, int count, String packageName, String className) {
+        Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
+        intent.putExtra("badge_count", count);
+        intent.putExtra("badge_count_package_name", packageName);
+        intent.putExtra("badge_count_class_name", className);
+        context.sendBroadcast(intent);
+    }
+
+    /**
+     * 重置Badge
+     *
+     * @param context context
+     */
+    public static void resetBadgeCount(Context context, int iconResId) {
+        setBadgeCount(context, 0, iconResId);
+    }
+}

+ 42 - 0
shortcut_lib/src/main/java/com/xys/shortcut_lib/FlowEntranceUtil.java

@@ -0,0 +1,42 @@
+package com.xys.shortcut_lib;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+/**
+ * Created by xuyisheng on 15/10/30.
+ * Version 1.0
+ */
+public final class FlowEntranceUtil {
+
+    private FlowEntranceUtil() throws InstantiationException {
+        throw new InstantiationException("This class is not for instantiation");
+    }
+
+    /**
+     * 显示\隐藏Launcher入口
+     *
+     * @param context       context
+     * @param launcherClass launcherClass
+     */
+    public static void toggleFlowEntrance(Context context, Class launcherClass) {
+        PackageManager packageManager = context.getPackageManager();
+        ComponentName componentName = new ComponentName(context, launcherClass);
+        int res = packageManager.getComponentEnabledSetting(componentName);
+        if (res == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT ||
+                res == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+            // 隐藏应用图标
+            packageManager.setComponentEnabledSetting(
+                    componentName,
+                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                    PackageManager.DONT_KILL_APP);
+        } else {
+            // 显示应用图标
+            packageManager.setComponentEnabledSetting(
+                    componentName,
+                    PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+                    PackageManager.DONT_KILL_APP);
+        }
+    }
+}

+ 93 - 0
shortcut_lib/src/main/java/com/xys/shortcut_lib/LauncherUtil.java

@@ -0,0 +1,93 @@
+package com.xys.shortcut_lib;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.text.TextUtils;
+
+import java.util.List;
+
+/**
+ * Function: LauncherUtil
+ * Create date on 15/8/17.
+ *
+ * @version 1.0
+ */
+public final class LauncherUtil {
+
+    private static String mBufferedValue = null;
+
+    private LauncherUtil() throws InstantiationException {
+      throw new InstantiationException("This class is not for instantiation");  
+    }
+
+    /**
+     * get the current Launcher's Package Name
+     */
+    public static String getCurrentLauncherPackageName(Context context) {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_HOME);
+        ResolveInfo res = context.getPackageManager().resolveActivity(intent, 0);
+        if (res == null || res.activityInfo == null) {
+            // should not happen. A home is always installed, isn't it?
+            return "";
+        }
+        if (res.activityInfo.packageName.equals("android")) {
+            return "";
+        } else {
+            return res.activityInfo.packageName;
+        }
+    }
+
+    /**
+     * default permission is "com.android.launcher.permission.READ_SETTINGS"<br/>
+     * {@link #getAuthorityFromPermission(Context, String)}<br/>
+     *
+     * @param context context
+     */
+    public static String getAuthorityFromPermissionDefault(Context context) {
+        if (TextUtils.isEmpty(mBufferedValue))//we get value buffered
+            mBufferedValue = getAuthorityFromPermission(context, "com.android.launcher.permission.READ_SETTINGS");
+        return mBufferedValue;
+    }
+
+    /**
+     * be cautious to use this, it will cost about 500ms 此函数为费时函数,大概占用500ms左右的时间<br/>
+     * android系统桌面的基本信息由一个launcher.db的Sqlite数据库管理,里面有三张表<br/>
+     * 其中一张表就是favorites。这个db文件一般放在data/data/com.android.launcher(launcher2)文件的databases下<br/>
+     * 但是对于不同的rom会放在不同的地方<br/>
+     * 例如MIUI放在data/data/com.miui.home/databases下面<br/>
+     * htc放在data/data/com.htc.launcher/databases下面<br/
+     *
+     * @param context    context
+     * @param permission 读取设置的权限  READ_SETTINGS_PERMISSION
+     * @return permission
+     */
+    public static String getAuthorityFromPermission(Context context, String permission) {
+        if (TextUtils.isEmpty(permission)) {
+            return "";
+        }
+        try {
+            List<PackageInfo> packs = context.getPackageManager().getInstalledPackages(PackageManager.GET_PROVIDERS);
+            if (packs == null) {
+                return "";
+            }
+            for (PackageInfo pack : packs) {
+                ProviderInfo[] providers = pack.providers;
+                if (providers != null) {
+                    for (ProviderInfo provider : providers) {
+                        if (permission.equals(provider.readPermission) || permission.equals(provider.writePermission)) {
+                            return provider.authority;
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+}

+ 246 - 0
shortcut_lib/src/main/java/com/xys/shortcut_lib/ShortcutSuperUtils.java

@@ -0,0 +1,246 @@
+package com.xys.shortcut_lib;
+
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Created by xuyisheng on 15/11/6.
+ * version 1.0
+ */
+public final class ShortcutSuperUtils {
+
+    private ShortcutSuperUtils() throws InstantiationException {
+        throw new InstantiationException("This class is not for instantiation");
+    }
+
+    /**
+     * 判断快捷方式是否存在
+     * <p/>
+     * 检查快捷方式是否存在 <br/>
+     * <font color=red>注意:</font> 有些手机无法判断是否已经创建过快捷方式<br/>
+     * 因此,在创建快捷方式时,请添加<br/>
+     * shortcutIntent.putExtra("duplicate", false);// 不允许重复创建<br/>
+     * 最好使用{@link #isShortCutExist(Context, String, Intent)}
+     * 进行判断,因为可能有些应用生成的快捷方式名称是一样的的<br/>
+     *
+     * @param context context
+     * @param title   快捷方式名
+     * @return 是否存在
+     */
+    public static boolean isShortCutExist(Context context, String title) {
+        boolean result = false;
+        try {
+            ContentResolver cr = context.getContentResolver();
+            Uri uri = getUriFromLauncher(context);
+            Cursor c = cr.query(uri, new String[]{"title"}, "title=? ", new String[]{title}, null);
+            if (c != null && c.getCount() > 0) {
+                result = true;
+            }
+            if (c != null && !c.isClosed()) {
+                c.close();
+            }
+        } catch (Exception e) {
+            result = false;
+            e.printStackTrace();
+        }
+        return result;
+    }
+
+    /**
+     * 判断快捷方式是否存在
+     * <p/>
+     * 不一定所有的手机都有效,因为国内大部分手机的桌面不是系统原生的<br/>
+     * 更多请参考{@link #isShortCutExist(Context, String)}<br/>
+     * 桌面有两种,系统桌面(ROM自带)与第三方桌面,一般只考虑系统自带<br/>
+     * 第三方桌面如果没有实现系统响应的方法是无法判断的,比如GO桌面<br/>
+     *
+     * @param context context
+     * @param title   快捷方式名
+     * @param intent  快捷方式Intent
+     * @return 是否存在
+     */
+    public static boolean isShortCutExist(Context context, String title, Intent intent) {
+        boolean result = false;
+        try {
+            ContentResolver cr = context.getContentResolver();
+            Uri uri = getUriFromLauncher(context);
+            Cursor c = cr.query(uri, new String[]{"title", "intent"}, "title=?  and intent=?",
+                    new String[]{title, intent.toUri(0)}, null);
+            if (c != null && c.getCount() > 0) {
+                result = true;
+            }
+            if (c != null && !c.isClosed()) {
+                c.close();
+            }
+        } catch (Exception ex) {
+            result = false;
+            ex.printStackTrace();
+        }
+        return result;
+    }
+
+    /**
+     * 更新桌面快捷方式图标,不一定所有图标都有效(有可能需要系统权限)
+     *
+     * @param context context
+     * @param title   快捷方式名
+     * @param intent  快捷方式Intent
+     * @param bitmap  快捷方式Icon
+     */
+    public static void updateShortcutIcon(Context context, String title, Intent intent, Bitmap bitmap) {
+        if (bitmap == null) {
+            Log.i("HJ", "update shortcut icon,bitmap empty");
+            return;
+        }
+        try {
+            ContentResolver cr = context.getContentResolver();
+            Uri uri = getUriFromLauncher(context);
+            Cursor c = cr.query(uri, new String[]{"_id", "title", "intent"},
+                    "title=?  and intent=? ",
+                    new String[]{title, intent.toUri(0)}, null);
+            int index = -1;
+            if (c != null && c.getCount() > 0) {
+                c.moveToFirst();
+                index = c.getInt(0);//获得图标索引
+                ContentValues cv = new ContentValues();
+                cv.put("icon", flattenBitmap(bitmap));
+                Uri uri2 = Uri.parse(uri.toString() + "/favorites/" + index + "?notify=true");
+                int i = context.getContentResolver().update(uri2, cv, null, null);
+                context.getContentResolver().notifyChange(uri, null);//此处不能用uri2,是个坑
+                Log.i("HJ", "update ok: affected " + i + " rows,index is" + index);
+            } else {
+                Log.i("HJ", "update result failed");
+            }
+            if (c != null && !c.isClosed()) {
+                c.close();
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            Log.i("HJ", "update shortcut icon,get errors:" + ex.getMessage());
+        }
+    }
+
+    private static byte[] flattenBitmap(Bitmap bitmap) {
+        // Try go guesstimate how much space the icon will take when serialized
+        // to avoid unnecessary allocations/copies during the write.
+        int size = bitmap.getWidth() * bitmap.getHeight() * 4;
+        ByteArrayOutputStream out = new ByteArrayOutputStream(size);
+        try {
+            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
+            out.flush();
+            out.close();
+            return out.toByteArray();
+        } catch (IOException e) {
+            Log.w("HJ", "Could not write icon");
+            return null;
+        }
+    }
+
+    private static Uri getUriFromLauncher(Context context) {
+        StringBuilder uriStr = new StringBuilder();
+        String authority = LauncherUtil.getAuthorityFromPermissionDefault(context);
+        if (authority == null || authority.trim().equals("")) {
+            authority = LauncherUtil.getAuthorityFromPermission(context, LauncherUtil.getCurrentLauncherPackageName(context) + ".permission.READ_SETTINGS");
+        }
+        uriStr.append("content://");
+        if (TextUtils.isEmpty(authority)) {
+            int sdkInt = android.os.Build.VERSION.SDK_INT;
+            if (sdkInt < 8) { // Android 2.1.x(API 7)以及以下的
+                uriStr.append("com.android.launcher.settings");
+            } else if (sdkInt < 19) {// Android 4.4以下
+                uriStr.append("com.android.launcher2.settings");
+            } else {// 4.4以及以上
+                uriStr.append("com.android.launcher3.settings");
+            }
+        } else {
+            uriStr.append(authority);
+        }
+        uriStr.append("/favorites?notify=true");
+        return Uri.parse(uriStr.toString());
+    }
+
+    /**
+     * 为任意PackageName的App添加快捷方式
+     *
+     * @param context context
+     * @param pkg     待添加快捷方式的应用包名
+     * @return 返回true为正常执行完毕
+     */
+    public static boolean addShortcutByPackageName(Context context, String pkg) {
+        // 快捷方式名
+        String title = "unknown";
+        // MainActivity完整名
+        String mainAct = null;
+        // 应用图标标识
+        int iconIdentifier = 0;
+        // 根据包名寻找MainActivity
+        PackageManager pkgMag = context.getPackageManager();
+        Intent queryIntent = new Intent(Intent.ACTION_MAIN, null);
+        queryIntent.addCategory(Intent.CATEGORY_LAUNCHER);// 重要,添加后可以进入直接已经打开的页面
+        queryIntent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+        queryIntent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
+
+        List<ResolveInfo> list = pkgMag.queryIntentActivities(queryIntent,
+                PackageManager.GET_ACTIVITIES);
+        for (int i = 0; i < list.size(); i++) {
+            ResolveInfo info = list.get(i);
+            if (info.activityInfo.packageName.equals(pkg)) {
+                title = info.loadLabel(pkgMag).toString();
+                mainAct = info.activityInfo.name;
+                iconIdentifier = info.activityInfo.applicationInfo.icon;
+                break;
+            }
+        }
+        if (mainAct == null) {
+            // 没有启动类
+            return false;
+        }
+        Intent shortcut = new Intent(
+                "com.android.launcher.action.INSTALL_SHORTCUT");
+        // 快捷方式的名称
+        shortcut.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
+        // 不允许重复创建
+        shortcut.putExtra("duplicate", false);
+        ComponentName comp = new ComponentName(pkg, mainAct);
+        shortcut.putExtra(Intent.EXTRA_SHORTCUT_INTENT,
+                queryIntent.setComponent(comp));
+        // 快捷方式的图标
+        Context pkgContext = null;
+        if (context.getPackageName().equals(pkg)) {
+            pkgContext = context;
+        } else {
+            // 创建第三方应用的上下文环境,为的是能够根据该应用的图标标识符寻找到图标文件。
+            try {
+                pkgContext = context.createPackageContext(pkg,
+                        Context.CONTEXT_IGNORE_SECURITY
+                                | Context.CONTEXT_INCLUDE_CODE);
+            } catch (PackageManager.NameNotFoundException e) {
+                e.printStackTrace();
+            }
+        }
+        if (pkgContext != null) {
+            Intent.ShortcutIconResource iconRes = Intent.ShortcutIconResource
+                    .fromContext(pkgContext, iconIdentifier);
+            shortcut.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconRes);
+        }
+        // 发送广播,让接收者创建快捷方式
+        // 需权限<uses-permission
+        // android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
+        context.sendBroadcast(shortcut);
+        return true;
+    }
+}

+ 61 - 0
shortcut_lib/src/main/java/com/xys/shortcut_lib/ShortcutUtils.java

@@ -0,0 +1,61 @@
+package com.xys.shortcut_lib;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+
+/**
+ * Created by xuyisheng on 15/10/30.
+ * Version 1.0
+ */
+public final class ShortcutUtils {
+
+    // Action 添加Shortcut
+    public static final String ACTION_ADD_SHORTCUT = "com.android.launcher.action.INSTALL_SHORTCUT";
+    // Action 移除Shortcut
+    public static final String ACTION_REMOVE_SHORTCUT = "com.android.launcher.action.UNINSTALL_SHORTCUT";
+
+    private ShortcutUtils() throws InstantiationException {
+        throw new InstantiationException("This class is not for instantiation");
+    }
+
+    /**
+     * 添加快捷方式
+     *
+     * @param context      context
+     * @param actionIntent 要启动的Intent
+     * @param name         name
+     * @param allowRepeat  是否允许重复
+     * @param iconBitmap   快捷方式图标
+     */
+    public static void addShortcut(Context context, Intent actionIntent, String name,
+                                   boolean allowRepeat, Bitmap iconBitmap) {
+        Intent addShortcutIntent = new Intent(ACTION_ADD_SHORTCUT);
+        // 是否允许重复创建
+        addShortcutIntent.putExtra("duplicate", allowRepeat);
+        // 快捷方式的标题
+        addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
+        // 快捷方式的图标
+        addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, iconBitmap);
+        // 快捷方式的动作
+        addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, actionIntent);
+        context.sendBroadcast(addShortcutIntent);
+    }
+
+    /**
+     * 移除快捷方式
+     *
+     * @param context      context
+     * @param actionIntent 要启动的Intent
+     * @param name         name
+     */
+    public static void removeShortcut(Context context, Intent actionIntent, String name) {
+        Intent intent = new Intent(ACTION_REMOVE_SHORTCUT);
+        intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
+//        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        intent.putExtra("duplicate", false);
+        intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, actionIntent);
+        context.sendBroadcast(intent);
+    }
+
+}

+ 15 - 0
shortcut_lib/src/test/java/com/xys/shortcut_lib/ExampleUnitTest.java

@@ -0,0 +1,15 @@
+package com.xys.shortcut_lib;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * To work on unit tests, switch the Test Artifact in the Build Variants view.
+ */
+public class ExampleUnitTest {
+    @Test
+    public void addition_isCorrect() throws Exception {
+        assertEquals(4, 2 + 2);
+    }
+}