package com.xfhy.mobilesafe.activity;

import android.content.Intent;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageStats;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.text.format.Formatter;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.xfhy.mobilesafe.R;
import com.xfhy.mobilesafe.model.AppCacheInfo;
import com.xfhy.mobilesafe.utils.LogUtil;

import java.lang.reflect.Method;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * @author xfhy 2017年5月26日08:58:47
 *         缓存清理界面
 *         <p>
 *         本部分的知识点涉及到AIDL、Java反射机制。
 *         关于安装包得大小信息封装在PackageStats类中，该类很简单，只有几个字段.
 *         需要用到的aidl:
 *         <p>
 *         1. IPackageStatsObserver.aidl
 *         2. PackageStats.aidl
 *         <p>
 *         通过反射调用隐藏的getPackageSizeInfo()方法,然后传入IPackageStatsObserver.Stub实例,然后会在
 *         getPackageSizeInfo()方法里面调用onGetStatsCompleted()方法进行缓存大小的赋值.注意.里面是子线程.
 *         <p>
 *         本部分参考:http://www.jianshu.com/p/ee7a00e12b0b  感谢原作者分享
 */
public class CacheCleanupActivity extends BaseActivity implements View.OnClickListener {

    @BindView(R.id.bt_immedi_clean_up)
    Button btImmediCleanUp;
    @BindView(R.id.tv_scan_state)
    TextView tvScanState;
    @BindView(R.id.ll_add_app_item)
    LinearLayout llAddAppItem;
    @BindView(R.id.pb_scan_cache)
    ProgressBar pbScanCache;

    private IPackageStatsObserver.Stub mStatsObserver;
    private static final String TAG = "CacheCleanupActivity";
    private PackageManager mPm;

    private static final int UPDATE_APP_CACHE_ITEM = 1000;
    private static final int SCAN_FINISHED = 1001;
    private static final int SCAN_APP_NAME = 1002;
    private static final int REMOVE_ALL_APP_ITEM = 1003;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATE_APP_CACHE_ITEM:

                    //1, 加载布局  获取控件
                    View appItemView = View.inflate(getApplicationContext(), R.layout
                            .layout_appcache_info_item, null);
                    ImageView ivAppIcon = (ImageView) appItemView.findViewById(R.id.iv_app_icon);
                    TextView tvAppName = (TextView) appItemView.findViewById(R.id.tv_app_name);
                    TextView tvAppCacheSize = (TextView) appItemView.findViewById(R.id
                            .tv_app_cache_size);
                    ImageView ivClearCache = (ImageView) appItemView.findViewById(R.id
                            .iv_clear_cache);

                    //2, 获取传递过来的应用缓存信息
                    final AppCacheInfo appCacheInfo = (AppCacheInfo) msg.obj;
                    ivAppIcon.setImageDrawable(appCacheInfo.getIcon());
                    tvAppName.setText(appCacheInfo.getAppName());
                    tvAppCacheSize.setText(Formatter.formatFileSize(getApplicationContext(),
                            appCacheInfo.getCacheSize
                            ()));
                    //3, 将加载的布局加入到界面中  顶部
                    llAddAppItem.addView(appItemView, 0);

                    //后面那个垃圾箱 ImageView的点击事件
                    ivClearCache.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            //这里去调用系统的界面进行缓存清理
                            Intent intent = new Intent("android.settings" +
                                    ".APPLICATION_DETAILS_SETTINGS");
                            intent.setData(Uri.parse("package:"+appCacheInfo.getPackageName()));
                            startActivity(intent);
                        }
                    });

                    break;
                case SCAN_APP_NAME:
                    tvScanState.setText("正在扫描:" + msg.obj);
                    break;
                case SCAN_FINISHED:

                    tvScanState.setText("扫描完成");

                    break;
                case REMOVE_ALL_APP_ITEM:
                    llAddAppItem.removeAllViews();//移除所有子View
                    break;
            }
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cache_cleanup);
        ButterKnife.bind(this);

        initUI();
        initAllApp();
    }

    private void initUI() {
        btImmediCleanUp.setOnClickListener(this);
    }

    /**
     * 遍历所有应用
     */
    private void initAllApp() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //1, 获取包管理者对象
                mPm = getPackageManager();
                //2, 获取手机安装的所有包信息
                List<PackageInfo> installedPackages = mPm.getInstalledPackages(0);
                pbScanCache.setMax(installedPackages.size());
                int count = 0;
                //3, 循环遍历所有的包信息
                for (PackageInfo packageInfo : installedPackages) {
                    //4, 根据该包名获取该包名对应应用的缓存信息
                    getPackageCache(packageInfo.packageName);

                    //5, 睡一下  表现真实
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //6, 设置进度
                    pbScanCache.setProgress(++count);

                    //发送消息给主线程  通知正在扫描的应用程序
                    Message msg = Message.obtain();
                    msg.what = SCAN_APP_NAME;
                    try {
                        msg.obj = mPm.getApplicationInfo(packageInfo.packageName, 0).loadLabel(mPm)
                                .toString();
                    } catch (PackageManager.NameNotFoundException e) {
                        e.printStackTrace();
                    }
                    mHandler.sendMessage(msg);
                }

                //7, 扫描完成  发送消息到主线程
                Message msg = Message.obtain();
                msg.what = SCAN_FINISHED;
                mHandler.sendMessage(msg);
            }
        }).start();

    }

    /**
     * 获取对应包名所对应的应用的缓存大小 的方法
     *
     * @param packageName 包名
     */
    private void getPackageCache(String packageName) {

        mStatsObserver = new IPackageStatsObserver.Stub() {
            @Override
            public void onGetStatsCompleted(PackageStats pStats,
                                            boolean succeeded) throws RemoteException {
                //这里是子线程
                //赋值给缓存大小   这里的单位是byte
                long cacheSize = pStats.cacheSize;
                if (cacheSize > 0) {
                    //有些应用是没有缓存的   应该判断一下缓存大小是否大于0
                    AppCacheInfo appCacheInfo = new AppCacheInfo();
                    try {
                        //获取应用名称
                        appCacheInfo.setAppName(mPm.getApplicationInfo(pStats.packageName, 0)
                                .loadLabel
                                (mPm).toString());
                        //获取应用包名
                        appCacheInfo.setPackageName(pStats.packageName);
                        //获取应用图标
                        appCacheInfo.setIcon(mPm.getApplicationInfo(pStats.packageName, 0)
                                .loadIcon(mPm));
                        //获取应用缓存
                        appCacheInfo.setCacheSize(cacheSize);
                    } catch (PackageManager.NameNotFoundException e) {
                        e.printStackTrace();
                    }

                    //将刚刚得到的这个应用的缓存信息发送到主线程
                    Message msg = Message.obtain();
                    msg.what = UPDATE_APP_CACHE_ITEM;
                    msg.obj = appCacheInfo;
                    mHandler.sendMessage(msg);

                }
//                String str = Formatter.formatFileSize(getApplicationContext(), cacheSize);
//                LogUtil.d(TAG, "===================str = " + str);
            }
        };

//		源码: mPm.getPackageSizeInfo("com.android.broswer", mStatsObserver);
        try {
            //1, 加载PackageManager字节码
            Class<?> clazz = Class.forName("android.content.pm.PackageManager");
            //2, 获取getPackageSizeInfo()方法对象
            Method method = clazz.getMethod("getPackageSizeInfo", String.class,
                    IPackageStatsObserver.class);
            //3, 通过对象调方法
            method.invoke(mPm, packageName, mStatsObserver);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bt_immedi_clean_up:

                clearAllCache(); //清理所有缓存

                break;
        }
    }

    /**
     * 清理所有缓存
     */
    private void clearAllCache() {
        try {
            //1.获取指定类的字节码文件
            Class<?> clazz = Class.forName("android.content.pm.PackageManager");
            //2.获取调用方法对象 通过调用PackageManager里面的隐藏方法freeStorageAndNotify(),清理所有缓存
            //freeStorageAndNotify()参数是:a.需要释放的大小,这里申请一个很大的值,这样系统就会释放最大的空间
            //     b.IPackageDataObserver对象
            Method method = clazz.getMethod("freeStorageAndNotify", long.class,
                    IPackageDataObserver.class);
            //3.获取对象调用方法
            method.invoke(mPm, Long.MAX_VALUE, new IPackageDataObserver.Stub() {
                @Override
                public void onRemoveCompleted(String packageName, boolean succeeded)
                        throws RemoteException {
                    //清除缓存完成后调用的方法(这里需要权限:CLEAR_APP_CACHE)
                    Message msg = Message.obtain();
                    msg.what = REMOVE_ALL_APP_ITEM;
                    mHandler.sendMessage(msg);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
