/* * Copyright (C) 2011-2014 asksven * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.asksven.betterbatterystats.adapters; import java.util.ArrayList; import java.util.List; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityOptionsCompat; import android.util.Log; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.view.Window; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.asksven.android.common.privateapiproxies.NativeKernelWakelock; import com.asksven.android.common.kernelutils.State; import com.asksven.android.common.nameutils.UidNameResolver; import com.asksven.android.common.privateapiproxies.Alarm; import com.asksven.android.common.privateapiproxies.AlarmItem; import com.asksven.android.common.privateapiproxies.Misc; import com.asksven.android.common.privateapiproxies.NetworkUsage; import com.asksven.android.common.privateapiproxies.Process; import com.asksven.android.common.privateapiproxies.SensorUsage; import com.asksven.android.common.privateapiproxies.SensorUsageItem; import com.asksven.android.common.privateapiproxies.StatElement; import com.asksven.betterbatterystats.widgets.GraphableBars; import com.asksven.betterbatterystats.widgets.GraphablePie; import com.asksven.betterbatterystats.LogSettings; import com.asksven.betterbatterystats.PackageInfoActivity; import com.asksven.betterbatterystats.R; public class StatsAdapter extends BaseAdapter { private Context m_context; private List<StatElement> m_listData; private static final String TAG = "StatsAdapter"; public static final String TRANSITION_NAME = "icon_transition"; private double m_maxValue = 0; private long m_timeSince = 0; private Activity m_parent = null; public StatsAdapter(Context context, List<StatElement> listData, Activity parent) { this.m_context = context; this.m_listData = listData; this.m_parent = parent; SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this.m_context); boolean bKbEnabled = sharedPrefs.getBoolean("enable_kb", true); if ((m_listData != null) && (!m_listData.isEmpty())) { if (m_listData.get(0) instanceof NetworkUsage) { for (int i = 0; i < m_listData.size(); i++) { StatElement g = m_listData.get(i); double[] values = g.getValues(); m_maxValue = Math.max(m_maxValue, values[values.length - 1]); m_maxValue = Math.max(m_maxValue, g.getMaxValue()); } } else if (m_listData.get(0) instanceof Alarm) { for (int i = 0; i < m_listData.size(); i++) { StatElement g = m_listData.get(i); double[] values = g.getValues(); m_maxValue += values[0]; Log.i(TAG, "Summing up " + values[0] + ", max is now " + m_maxValue); } } else if (m_listData.get(0) instanceof SensorUsage) { for (int i = 0; i < m_listData.size(); i++) { StatElement g = m_listData.get(i); double[] values = g.getValues(); m_maxValue += values[0]; Log.i(TAG, "Summing up " + values[0] + ", max is now " + m_maxValue); } } else if (m_listData.get(0) instanceof Process) { StatElement g = m_listData.get(0); m_maxValue = g.getTotal(); Log.i(TAG, "Total is " + m_maxValue); } else { m_maxValue = m_timeSince; } } } public int getCount() { if (m_listData != null) { return m_listData.size(); } else { return 0; } } public Object getItem(int position) { return m_listData.get(position); } public void setTotalTime(long sinceMs) { m_timeSince = sinceMs; if ((m_listData == null) || (m_listData.isEmpty())) return; if (!((m_listData.get(0) instanceof Process) || (m_listData.get(0) instanceof NetworkUsage) || (m_listData.get(0) instanceof Alarm))) { m_maxValue = m_timeSince; } } public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup viewGroup) { StatElement entry = m_listData.get(position); SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this.m_context); boolean bShowBars = sharedPrefs.getBoolean("show_gauge", false); if (LogSettings.DEBUG) { Log.i(TAG, "Values: " +entry.getVals()); } if (convertView == null) { LayoutInflater inflater = (LayoutInflater) m_context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); // depending on settings show new pie gauge or old bar gauge if (!bShowBars) { convertView = inflater.inflate(R.layout.stat_row, null); } else { convertView = inflater.inflate(R.layout.stat_row_gauge, null); } } final float scale = this.m_context.getResources().getDisplayMetrics().density; TextView tvName = (TextView) convertView.findViewById(R.id.TextViewName); ///////////////////////////////////////// // we do some stuff here to handle settings about font size and thumbnail size String fontSize = sharedPrefs.getString("medium_font_size", "16"); int mediumFontSize = Integer.parseInt(fontSize); //we need to change "since" fontsize tvName.setTextSize(TypedValue.COMPLEX_UNIT_SP, mediumFontSize); // We need to handle an exception here: Sensors do not have a name so we use the fqn instead if (entry instanceof SensorUsage) { tvName.setText(entry.getFqn(UidNameResolver.getInstance(m_context))); } else { tvName.setText(entry.getName()); } boolean bShowKb = sharedPrefs.getBoolean("enable_kb", true); ImageView iconKb = (ImageView) convertView.findViewById(R.id.imageKB); iconKb.setVisibility(View.INVISIBLE); TextView tvFqn = (TextView) convertView.findViewById(R.id.TextViewFqn); tvFqn.setText(entry.getFqn(UidNameResolver.getInstance(m_context))); TextView tvData = (TextView) convertView.findViewById(R.id.TextViewData); // for alarms the values is wakeups per hour so we need to take the time as reference for the text if (entry instanceof Alarm) { tvData.setText(entry.getData((long)m_timeSince)); } else { tvData.setText(entry.getData((long)m_maxValue)); } //LinearLayout myLayout = (LinearLayout) convertView.findViewById(R.id.LinearLayoutBar); LinearLayout myFqnLayout = (LinearLayout) convertView.findViewById(R.id.LinearLayoutFqn); LinearLayout myRow = (LinearLayout) convertView.findViewById(R.id.LinearLayoutEntry); // long press for "copy to clipboard" convertView.setOnLongClickListener(new OnItemLongClickListener(position)); if (!bShowBars) { GraphablePie gauge = (GraphablePie) convertView.findViewById(R.id.Gauge); ///////////////////////////////////////// // we do some stuff here to handle settings about font size and thumbnail size String iconDim = sharedPrefs.getString("thumbnail_size", "56"); int iconSize = Integer.parseInt(iconDim); int pixels = (int) (iconSize * scale + 0.5f); //we need to change "since" fontsize gauge.getLayoutParams().height = pixels; gauge.getLayoutParams().width = pixels; gauge.requestLayout(); //////////////////////////////////////////////////////////////////////////////////// if (entry instanceof NetworkUsage) { gauge.setValue(entry.getValues()[0], ((NetworkUsage) entry).getTotal()); } else { double max = m_maxValue; // avoid rounding errors leading to values > 100 % if (entry.getValues()[0] > max) { max = entry.getValues()[0]; Log.i(TAG, "Upping gauge max to " + max); } gauge.setValue(entry.getValues()[0], max); } } else { GraphableBars buttonBar = (GraphableBars) convertView.findViewById(R.id.ButtonBar); int iHeight = 10; try { iHeight = Integer.valueOf(sharedPrefs.getString("graph_bar_height", "10")); } catch (Exception e) { iHeight = 10; } if (iHeight == 0) { iHeight = 10; } buttonBar.setMinimumHeight(iHeight); buttonBar.setName(entry.getName()); buttonBar.setValues(entry.getValues(), m_maxValue); } ImageView iconView = (ImageView) convertView.findViewById(R.id.icon); LinearLayout iconLayout = (LinearLayout) convertView.findViewById(R.id.LayoutIcon); ///////////////////////////////////////// // we do some stuff here to handle settings about font size and thumbnail size String iconDim = sharedPrefs.getString("thumbnail_size", "56"); int iconSize = Integer.parseInt(iconDim); int pixels = (int) (iconSize * scale + 0.5f); //we need to change "since" fontsize iconView.getLayoutParams().width = pixels; iconView.getLayoutParams().height = pixels; iconView.requestLayout(); //n 20;setLay.setTextSize(TypedValue.COMPLEX_UNIT_DIP, iconSize); //////////////////////////////////////////////////////////////////////////////////// // add on click listener for the icon only if KB is enabled // if (bShowKb) // { // // set a click listener for the list // iconKb.setOnClickListener(new OnIconClickListener(position)); // } // show / hide fqn text if ((entry instanceof Process) || (entry instanceof State) || (entry instanceof Misc) || (entry instanceof NativeKernelWakelock) || (entry instanceof Alarm) || (entry instanceof SensorUsage)) { myFqnLayout.setVisibility(View.GONE); } else { myFqnLayout.setVisibility(View.VISIBLE); } // show / hide package icons (we show / hide the whole layout as it contains a margin that must be hidded as well if ((entry instanceof NativeKernelWakelock) || (entry instanceof State) || (entry instanceof Misc)) { iconView.setVisibility(View.GONE); } else { iconView.setVisibility(View.VISIBLE); iconView.setImageDrawable(entry.getIcon(UidNameResolver.getInstance(m_context))); // set a click listener for the list iconView.setOnClickListener(new OnPackageClickListener(position)); } // add on click listener for the list entry if details are availble if ( (entry instanceof Alarm) || (entry instanceof NativeKernelWakelock) || (entry instanceof SensorUsage)) { convertView.setOnClickListener(new OnItemClickListener(position)); } // // show / hide set dividers // ListView myList = (ListView) convertView.getListView(); //findViewById(R.id.id.list); // myList.setDivider(new ColorDrawable(0x99F10529)); // myList.setDividerHeight(1); return convertView; } // /** // * Handler for on click of the KB icon // * @author sven // * // */ // private class OnIconClickListener implements OnClickListener // { // private int m_iPosition; // OnIconClickListener(int position) // { // m_iPosition = position; // } // // @Override // public void onClick(View arg0) // { // StatElement entry = (StatElement) getItem(m_iPosition); // KbData kb = KbReader.getInstance().read(m_context); // // the timing may lead to m_kb not being initialized yet, it must be checked // if (kb == null) // { // return; // } // KbEntry kbentry = kb.findByStatElement(entry.getName(), entry.getFqn(UidNameResolver.getInstance(StatsAdapter.this.m_context))); // if (kbentry != null) // { // SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(StatsAdapter.this.m_context); // // String url = kbentry.getUrl(); // // if (sharedPrefs.getBoolean("kb_ext_browser", true)) // { // // Intent intent = new Intent("android.intent.action.VIEW", // Uri.parse(url)); // StatsAdapter.this.m_context.startActivity(intent); // } // else // { // Intent intentKB = new Intent(StatsAdapter.this.m_context, // HelpActivity.class); // intentKB.putExtra("url", url); // StatsAdapter.this.m_context.startActivity(intentKB); // } // } // } // } /** * Handler for on click of the icon * @author sven * */ private class OnPackageClickListener implements OnClickListener { private int m_iPosition; OnPackageClickListener(int position) { m_iPosition = position; } @Override public void onClick(View arg0) { StatElement entry = (StatElement) getItem(m_iPosition); Context ctx = arg0.getContext(); if (entry.getIcon(UidNameResolver.getInstance(m_context)) == null) { return; } // ctx.startActivity(new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)); String packageName = entry.getPackageName(); showInstalledPackageDetails(ctx, packageName, arg0); } } /** * Handler for the on click of the list item * @author sven * */ private class OnItemClickListener implements OnClickListener { private int m_iPosition; OnItemClickListener(int position) { m_iPosition = position; } @SuppressLint("NewApi") @Override public void onClick(View arg0) { StatElement entry = (StatElement) getItem(m_iPosition); if (entry instanceof SensorUsage) { SensorUsage sensorEntry = (SensorUsage) getItem(m_iPosition); Dialog dialog = new Dialog(m_context); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); dialog.setContentView(R.layout.details_dialog); TextView dialogTitle = (TextView) dialog.findViewById(R.id.dialog_title); dialogTitle.setText(entry.getFqn(UidNameResolver.getInstance(m_context))); TextView title = (TextView) dialog.findViewById(R.id.title); TextView text = (TextView) dialog.findViewById(R.id.text); title.setText(entry.getData((long)m_timeSince)); String strText = ""; ArrayList<SensorUsageItem> myItems = sensorEntry.getItems(); if (myItems != null) { for (int i=0; i<myItems.size(); i++) { if (myItems.get(i).getTime() > 0) { strText = strText + myItems.get(i).getData() + "\n\n"; } } } text.setText(strText); dialog.show(); } if (entry instanceof Alarm) { Alarm alarmEntry = (Alarm) getItem(m_iPosition); Dialog dialog = new Dialog(m_context); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); dialog.setContentView(R.layout.details_dialog); TextView dialogTitle = (TextView) dialog.findViewById(R.id.dialog_title); dialogTitle.setText(entry.getName()); TextView title = (TextView) dialog.findViewById(R.id.title); TextView text = (TextView) dialog.findViewById(R.id.text); title.setText(entry.getData((long)m_timeSince)); String strText = ""; ArrayList<AlarmItem> myItems = alarmEntry.getItems(); if (myItems != null) { for (int i=0; i<myItems.size(); i++) { if (myItems.get(i).getCount() > 0) { strText = strText + myItems.get(i).getData() + "\n\n"; } } } text.setText(strText); dialog.show(); } if (entry instanceof NativeKernelWakelock) { NativeKernelWakelock kernelWakelockEntry = (NativeKernelWakelock) getItem(m_iPosition); Dialog dialog = new Dialog(m_context); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); dialog.setContentView(R.layout.details_dialog); dialog.setTitle(kernelWakelockEntry.getName()); TextView dialogTitle = (TextView) dialog.findViewById(R.id.dialog_title); dialogTitle.setText(kernelWakelockEntry.getName()); TextView title = (TextView) dialog.findViewById(R.id.title); // TextView subtitle = (TextView) dialog.findViewById(R.id.subtitle); TextView text = (TextView) dialog.findViewById(R.id.text); title.setText(kernelWakelockEntry.getData((long)m_maxValue)); String strText = ""; strText += "Count: " + kernelWakelockEntry.getCount() + "\n"; strText += "Expire Count: " + kernelWakelockEntry.getExpireCount() + "\n"; strText += "Wake Count: " + kernelWakelockEntry.getWakeCount() + "\n"; strText += "Total Time: "+ kernelWakelockEntry.getTtlTime() + "\n"; strText += "Sleep Time: " + kernelWakelockEntry.getSleepTime() + "\n"; strText += "Max Time: " + kernelWakelockEntry.getMaxTime() + "\n"; text.setText(strText); dialog.show(); } } } /** * Handler for the on click of the list item * @author sven * */ private class OnItemLongClickListener implements OnLongClickListener { private int m_iPosition; OnItemLongClickListener(int position) { m_iPosition = position; } @SuppressLint("NewApi") @Override public boolean onLongClick(View arg0) { StatElement entry = (StatElement) getItem(m_iPosition); if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) { android.text.ClipboardManager clipboard = (android.text.ClipboardManager) m_context.getSystemService(Context.CLIPBOARD_SERVICE); clipboard.setText(entry.getName()); } else { android.content.ClipboardManager clipboard = (android.content.ClipboardManager) m_context.getSystemService(Context.CLIPBOARD_SERVICE); android.content.ClipData clip = android.content.ClipData.newPlainText("Copied Text", entry.getName()); clipboard.setPrimaryClip(clip); } try { Toast.makeText(m_context, m_context.getString(R.string.message_copied_to_clipboard, entry.getName()), Toast.LENGTH_LONG).show(); } catch (Exception e) { // can normally not fail, if it still does it's only the toast } return true; } } public void showInstalledPackageDetails(Context context, String packageName, View view) { Intent intentPerms = new Intent(context, PackageInfoActivity.class); intentPerms.putExtra("package", packageName); //context.startActivity(intentPerms); View source_icon = view.findViewById(R.id.icon); ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation( m_parent, source_icon, TRANSITION_NAME); ActivityCompat.startActivity(m_parent, intentPerms, options.toBundle()); } }