/* Copyright Statement: * * This software/firmware and related documentation ("MediaTek Software") are * protected under relevant copyright laws. The information contained herein is * confidential and proprietary to MediaTek Inc. and/or its licensors. Without * the prior written permission of MediaTek inc. and/or its licensors, any * reproduction, modification, use or disclosure of MediaTek Software, and * information contained herein, in whole or in part, shall be strictly * prohibited. * * MediaTek Inc. (C) 2010. All rights reserved. * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. * * The following software/firmware and/or related documentation ("MediaTek * Software") have been modified by MediaTek Inc. All revisions are subject to * any receiver's applicable license agreements with MediaTek Inc. */ package com.android.launcher3; import android.app.ActionBar; import android.app.ListActivity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.IPackageStatsObserver; import android.content.pm.PackageStats; import android.graphics.Bitmap; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.Process; import android.text.format.Formatter; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import com.android.launcher3.R; import com.mediatek.launcher3.ext.LauncherLog; import java.util.ArrayList; import java.util.HashMap; /** * M: this activity is used to configure hide applications, for op09. */ public class HideAppsActivity extends ListActivity implements AdapterView.OnItemClickListener { private static final String TAG = "HideAppsActivity"; static final String ACTION_PACKAGE_CHANGED = "package_list_changed"; static final String CHANGED_PAGES = "changedPages"; private static final int SIZE_UNKNOWN = -1; private static final int SIZE_INVALID = -2; private ArrayList<AppInfo> mApps = new ArrayList<AppInfo>(); //Used to recorder all apps original state when enter HideAppsActivity. private ArrayList<Boolean> mOriginalState = new ArrayList<Boolean>(); private AppsAdapter mAdapter; private HashMap<String, AppEntry> mEntriesMap = new HashMap<String, AppEntry>(); private HandlerThread mThread; private BackgroundHandler mHandler; private final BroadcastReceiver mPackageChangeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (ACTION_PACKAGE_CHANGED.equals(action)) { init(); mAdapter.notifyDataSetChanged(); } } }; public static class SizeInfo { long cacheSize; long codeSize; long dataSize; long externalCodeSize; long externalDataSize; // This is the part of externalDataSize that is in the cache // section of external storage. Note that we don't just combine // this with cacheSize because currently the platform can't // automatically trim this data when needed, so it is something // the user may need to manage. The externalDataSize also includes // this value, since what this is here is really the part of // externalDataSize that we can just consider to be "cache" files // for purposes of cleaning them up in the app details UI. long externalCacheSize; } public static class AppEntry extends SizeInfo { AppInfo info; long size; long internalSize; long externalSize; String sizeStr; String internalSizeStr; String externalSizeStr; AppEntry(AppInfo appInfo) { this.info = appInfo; this.size = SIZE_UNKNOWN; } } class BackgroundHandler extends Handler { static final int MSG_LOAD_SIZE = 0x0001; final IPackageStatsObserver.Stub mStatsObserver = new IPackageStatsObserver.Stub() { public void onGetStatsCompleted(PackageStats stats, boolean succeeded) { synchronized (mEntriesMap) { boolean sizeChanged = false; AppEntry entry = mEntriesMap.get(stats.packageName); if (entry != null) { long externalCodeSize = stats.externalCodeSize + stats.externalObbSize; long externalDataSize = stats.externalDataSize + stats.externalMediaSize + stats.externalCacheSize; long newSize = externalCodeSize + externalDataSize + getTotalInternalSize(stats); if (entry.size != newSize || entry.cacheSize != stats.cacheSize || entry.codeSize != stats.codeSize || entry.dataSize != stats.dataSize || entry.externalCodeSize != externalCodeSize || entry.externalDataSize != externalDataSize || entry.externalCacheSize != stats.externalCacheSize) { entry.size = newSize; entry.cacheSize = stats.cacheSize; entry.codeSize = stats.codeSize; entry.dataSize = stats.dataSize; entry.externalCodeSize = externalCodeSize; entry.externalDataSize = externalDataSize; entry.externalCacheSize = stats.externalCacheSize; entry.internalSize = getTotalInternalSize(stats); entry.externalSize = getTotalExternalSize(stats); sizeChanged = true; } // Update size info entry.sizeStr = getSizeStr(entry.size); entry.internalSizeStr = getSizeStr(entry.internalSize); entry.externalSizeStr = getSizeStr(entry.externalSize); if (sizeChanged) { // Update the listview item text notifyDataChanged(); } // Query another one if needed Message msg = mHandler.obtainMessage(MSG_LOAD_SIZE); mHandler.sendMessage(msg); } } } }; BackgroundHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_LOAD_SIZE: synchronized (mEntriesMap) { String pkgName = requestComputePkgSize(); if (pkgName != null) { HideAppsActivity.this.getPackageManager().getPackageSizeInfo(pkgName, mStatsObserver); } } break; default: break; } } String requestComputePkgSize() { final int appSize = mApps.size(); for (int i = 0; i < appSize; i++) { String pkgName = mApps.get(i).componentName.getPackageName(); if (pkgName != null) { AppEntry entry = mEntriesMap.get(pkgName); if (entry != null && entry.size == SIZE_UNKNOWN) { // Initilized size to be shown for user entry.size = 0; return pkgName; } } } return null; } } private void notifyDataChanged() { if (mAdapter != null) { getListView().post(new Runnable() { @Override public void run() { mAdapter.notifyDataSetChanged(); } }); } } private String getSizeStr(long size) { if (size >= 0) { return Formatter.formatFileSize(this, size); } return null; } private long getTotalInternalSize(PackageStats ps) { if (ps != null) { return ps.codeSize + ps.dataSize; } return SIZE_INVALID; } private long getTotalExternalSize(PackageStats ps) { if (ps != null) { return ps.externalCodeSize + ps.externalDataSize + ps.externalMediaSize + ps.externalObbSize; } return SIZE_INVALID; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.hide_list); mThread = new HandlerThread("HideAppsActivity.worker", Process.THREAD_PRIORITY_BACKGROUND); mThread.start(); mHandler = new BackgroundHandler(mThread.getLooper()); // Get all apps information, icon, title, size, show or hide? init(); mAdapter = new AppsAdapter(this); setListAdapter(mAdapter); getListView().setOnItemClickListener(this); getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); final IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_PACKAGE_CHANGED); registerReceiver(mPackageChangeReceiver, filter); } @Override protected void onPause() { backToHome(); super.onPause(); } @Override public void onDestroy() { if (LauncherLog.DEBUG) { LauncherLog.d(TAG, "onDestroy."); } unregisterReceiver(mPackageChangeReceiver); super.onDestroy(); } private void init() { if (!mApps.isEmpty()) { mApps.clear(); } if (!mEntriesMap.isEmpty()) { mEntriesMap.clear(); } if (mThread.isAlive()) { mThread.interrupt(); } ArrayList<AppInfo> allApps = AppsCustomizePagedView.mApps; for (int i = 0; i < allApps.size(); i++) { AppInfo info = allApps.get(i); mApps.add(info); } // Now all apps are present. int index = 0; final int appSize = mApps.size(); for (int i = 0; i < appSize; i++) { AppInfo info = mApps.get(i); // For query package physical memory size quickly mEntriesMap.put(info.componentName.getPackageName(), new AppEntry(info)); if (info != null) { info.stateChanged = false; mOriginalState.add(info.isVisible); } } if (LauncherLog.DEBUG_EDIT) { LauncherLog.d(TAG, "init end: appSize = " + appSize + ",mApps = " + mApps); } // Now start to query package size mHandler.sendEmptyMessage(BackgroundHandler.MSG_LOAD_SIZE); } @Override protected void onStart() { super.onStart(); final ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: backToHome(); break; default: break; } return true; } private void backToHome() { if (LauncherLog.DEBUG_EDIT) { LauncherLog.d(TAG, "backToHome: AppsCustomizePagedView.sShowAndHideApps = " + AppsCustomizePagedView.sShowAndHideApps); } if (AppsCustomizePagedView.sShowAndHideApps.size() == 0) { getStateChangedPages(); } if (AppsCustomizePagedView.sShowAndHideApps.size() > 0) { setResult(RESULT_OK); } else { setResult(RESULT_CANCELED); } finish(); } /** * Get pages in which there is application visible state changes. * * @return */ private ArrayList<Integer> getStateChangedPages() { ArrayList<Integer> pages = new ArrayList<Integer>(); int index = 0; final int size = mApps.size(); for (int i = 0; i < size; i++) { AppInfo info = mApps.get(i); if (mOriginalState.get(index++) != info.isVisible) { AppsCustomizePagedView.sShowAndHideApps.add(info); } } return pages; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ViewHolder holder = (ViewHolder) view.getTag(); holder.hide.toggle(); // State changes if the visible states equals the check status(hide). mApps.get(position).isVisible = !holder.hide.isChecked(); } @Override public void onBackPressed() { backToHome(); } class AppsAdapter extends BaseAdapter { private final LayoutInflater mInflater; AppsAdapter(Context context) { mInflater = LayoutInflater.from(context); } public int getCount() { return mApps.size(); } public Object getItem(int position) { return mApps.get(position); } public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { convertView = mInflater.inflate(R.layout.hide_entry, parent, false); holder = new ViewHolder(); holder.icon = (ImageView) convertView.findViewById(R.id.app_icon); holder.title = (TextView) convertView.findViewById(R.id.app_name); holder.size = (TextView) convertView.findViewById(R.id.app_size); holder.hide = (CheckBox) convertView.findViewById(R.id.hide); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } final Bitmap iconBitmap = mApps.get(position).iconBitmap; if (iconBitmap != null) { holder.icon.setVisibility(View.VISIBLE); holder.icon.setImageBitmap(iconBitmap); } else { holder.icon.setVisibility(View.GONE); } holder.title.setText(mApps.get(position).title); holder.hide.setChecked(!mApps.get(position).isVisible); // Now used to display app's memory size. holder.size.setText(mEntriesMap.get(mApps.get(position).componentName .getPackageName()).sizeStr); return convertView; } } static class ViewHolder { ImageView icon; TextView title; TextView size; CheckBox hide; } }