diff --git a/res/layout/battery_active_view.xml b/res/layout/battery_active_view.xml new file mode 100644 index 00000000000..b5ada00ed61 --- /dev/null +++ b/res/layout/battery_active_view.xml @@ -0,0 +1,37 @@ + + + + + + + + + + diff --git a/res/layout/battery_history_detail.xml b/res/layout/battery_history_detail.xml new file mode 100644 index 00000000000..d1563bf5d51 --- /dev/null +++ b/res/layout/battery_history_detail.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/android/settings/fuelgauge/BatteryActiveView.java b/src/com/android/settings/fuelgauge/BatteryActiveView.java new file mode 100644 index 00000000000..4856b3d3db3 --- /dev/null +++ b/src/com/android/settings/fuelgauge/BatteryActiveView.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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.android.settings.fuelgauge; + +import android.annotation.Nullable; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.util.SparseIntArray; +import android.view.View; + +public class BatteryActiveView extends View { + + private final Paint mPaint = new Paint(); + private BatteryActiveProvider mProvider; + + public BatteryActiveView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public void setProvider(BatteryActiveProvider provider) { + mProvider = provider; + if (getWidth() != 0) { + postInvalidate(); + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if (getWidth() != 0) { + postInvalidate(); + } + } + + @Override + protected void onDraw(Canvas canvas) { + if (mProvider == null) { + return; + } + SparseIntArray array = mProvider.getColorArray(); + float period = mProvider.getPeriod(); + for (int i = 0; i < array.size() - 1; i++) { + drawColor(canvas, array.keyAt(i), array.keyAt(i + 1), array.valueAt(i), period); + } + } + + private void drawColor(Canvas canvas, int start, int end, int color, float period) { + if (color == 0) { + return; + } + mPaint.setColor(color); + canvas.drawRect(start / period * getWidth(), 0, end / period * getWidth(), getHeight(), + mPaint); + } + + public interface BatteryActiveProvider { + boolean hasData(); + long getPeriod(); + SparseIntArray getColorArray(); + } +} diff --git a/src/com/android/settings/fuelgauge/BatteryCellParser.java b/src/com/android/settings/fuelgauge/BatteryCellParser.java new file mode 100644 index 00000000000..aaac024f0cb --- /dev/null +++ b/src/com/android/settings/fuelgauge/BatteryCellParser.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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.android.settings.fuelgauge; + +import android.os.BatteryStats.HistoryItem; +import android.telephony.ServiceState; +import android.util.SparseIntArray; +import com.android.settings.Utils; +import com.android.settings.fuelgauge.BatteryActiveView.BatteryActiveProvider; +import com.android.settingslib.BatteryInfo; + +public class BatteryCellParser implements BatteryInfo.BatteryDataParser, BatteryActiveProvider { + + private final SparseIntArray mData = new SparseIntArray(); + + private int mLastValue; + private long mLength; + private long mLastTime; + + protected int getValue(HistoryItem rec) { + int bin; + if (((rec.states & HistoryItem.STATE_PHONE_STATE_MASK) + >> HistoryItem.STATE_PHONE_STATE_SHIFT) + == ServiceState.STATE_POWER_OFF) { + bin = 0; + } else if ((rec.states & HistoryItem.STATE_PHONE_SCANNING_FLAG) != 0) { + bin = 1; + } else { + bin = (rec.states & HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK) + >> HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT; + bin += 2; + } + return bin; + } + + @Override + public void onParsingStarted(long startTime, long endTime) { + mLength = endTime - startTime; + } + + @Override + public void onDataPoint(long time, HistoryItem record) { + int value = getValue(record); + if (value != mLastValue) { + mData.put((int) time, value); + mLastValue = value; + } + mLastTime = time; + } + + @Override + public void onDataGap() { + if (mLastValue != 0) { + mData.put((int) mLastTime, 0); + mLastValue = 0; + } + } + + @Override + public void onParsingDone() { + if (mLastValue != 0) { + mData.put((int) mLastTime, 0); + mLastValue = 0; + } + } + + @Override + public long getPeriod() { + return mLength; + } + + @Override + public boolean hasData() { + return mData.size() > 1; + } + + @Override + public SparseIntArray getColorArray() { + SparseIntArray ret = new SparseIntArray(); + for (int i = 0; i < mData.size(); i++) { + ret.put(mData.keyAt(i), getColor(mData.valueAt(i))); + } + return ret; + } + + private int getColor(int i) { + return Utils.BADNESS_COLORS[i]; + } +} diff --git a/src/com/android/settings/fuelgauge/BatteryFlagParser.java b/src/com/android/settings/fuelgauge/BatteryFlagParser.java new file mode 100644 index 00000000000..cd5d89bd196 --- /dev/null +++ b/src/com/android/settings/fuelgauge/BatteryFlagParser.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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.android.settings.fuelgauge; + +import android.os.BatteryStats.HistoryItem; +import android.util.SparseBooleanArray; +import android.util.SparseIntArray; +import com.android.settings.fuelgauge.BatteryActiveView.BatteryActiveProvider; +import com.android.settingslib.BatteryInfo; + +public class BatteryFlagParser implements BatteryInfo.BatteryDataParser, BatteryActiveProvider { + + private final SparseBooleanArray mData = new SparseBooleanArray(); + private final int mFlag; + private final boolean mState2; + private final int mAccentColor; + + private boolean mLastSet; + private long mLength; + private long mLastTime; + + public BatteryFlagParser(int accent, boolean state2, int flag) { + mAccentColor = accent; + mFlag = flag; + mState2 = state2; + } + + protected boolean isSet(HistoryItem record) { + return ((mState2 ? record.states2 : record.states) & mFlag) != 0; + } + + @Override + public void onParsingStarted(long startTime, long endTime) { + mLength = endTime - startTime; + } + + @Override + public void onDataPoint(long time, HistoryItem record) { + boolean isSet = isSet(record); + if (isSet != mLastSet) { + mData.put((int) time, isSet); + mLastSet = isSet; + } + mLastTime = time; + } + + @Override + public void onDataGap() { + if (mLastSet) { + mData.put((int) mLastTime, false); + mLastSet = false; + } + } + + @Override + public void onParsingDone() { + if (mLastSet) { + mData.put((int) mLastTime, false); + mLastSet = false; + } + } + + @Override + public long getPeriod() { + return mLength; + } + + @Override + public boolean hasData() { + return mData.size() > 1; + } + + @Override + public SparseIntArray getColorArray() { + SparseIntArray ret = new SparseIntArray(); + for (int i = 0; i < mData.size(); i++) { + ret.put(mData.keyAt(i), getColor(mData.valueAt(i))); + } + return ret; + } + + private int getColor(boolean b) { + if (b) { + return mAccentColor; + } + return 0; + } +} diff --git a/src/com/android/settings/fuelgauge/BatteryHistoryDetail.java b/src/com/android/settings/fuelgauge/BatteryHistoryDetail.java index af135512331..b2cb73a9444 100644 --- a/src/com/android/settings/fuelgauge/BatteryHistoryDetail.java +++ b/src/com/android/settings/fuelgauge/BatteryHistoryDetail.java @@ -18,15 +18,21 @@ package com.android.settings.fuelgauge; import android.content.Intent; import android.os.BatteryStats; +import android.os.BatteryStats.HistoryItem; import android.os.Bundle; +import android.os.SystemClock; +import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; - +import android.widget.TextView; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.internal.os.BatteryStatsHelper; import com.android.settings.InstrumentedFragment; import com.android.settings.R; +import com.android.settings.fuelgauge.BatteryActiveView.BatteryActiveProvider; +import com.android.settingslib.BatteryInfo; +import com.android.settingslib.graph.UsageView; public class BatteryHistoryDetail extends InstrumentedFragment { public static final String EXTRA_STATS = "stats"; @@ -35,21 +41,80 @@ public class BatteryHistoryDetail extends InstrumentedFragment { private BatteryStats mStats; private Intent mBatteryBroadcast; + private BatteryFlagParser mChargingParser; + private BatteryFlagParser mScreenOn; + private BatteryFlagParser mGpsParser; + private BatteryFlagParser mFlashlightParser; + private BatteryFlagParser mCameraParser; + private BatteryWifiParser mWifiParser; + private BatteryFlagParser mCpuParser; + private BatteryCellParser mPhoneParser; + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); String histFile = getArguments().getString(EXTRA_STATS); mStats = BatteryStatsHelper.statsFromFile(getActivity(), histFile); mBatteryBroadcast = getArguments().getParcelable(EXTRA_BROADCAST); + + TypedValue value = new TypedValue(); + getContext().getTheme().resolveAttribute(android.R.attr.colorAccent, value, true); + int accentColor = getContext().getColor(value.resourceId); + + mChargingParser = new BatteryFlagParser(accentColor, false, + HistoryItem.STATE_BATTERY_PLUGGED_FLAG); + mScreenOn = new BatteryFlagParser(accentColor, false, + HistoryItem.STATE_SCREEN_ON_FLAG); + mGpsParser = new BatteryFlagParser(accentColor, false, + HistoryItem.STATE_GPS_ON_FLAG); + mFlashlightParser = new BatteryFlagParser(accentColor, true, + HistoryItem.STATE2_FLASHLIGHT_FLAG); + mCameraParser = new BatteryFlagParser(accentColor, true, + HistoryItem.STATE2_CAMERA_FLAG); + mWifiParser = new BatteryWifiParser(accentColor); + mCpuParser = new BatteryFlagParser(accentColor, false, + HistoryItem.STATE_CPU_RUNNING_FLAG); + mPhoneParser = new BatteryCellParser(); } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.battery_history_chart, null); - BatteryHistoryChart chart = (BatteryHistoryChart)view.findViewById( - R.id.battery_history_chart); - chart.setStats(mStats, mBatteryBroadcast); - return view; + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.battery_history_detail, container, false); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + updateEverything(); + } + + private void updateEverything() { + BatteryInfo info = BatteryInfo.getBatteryInfo(getContext(), mBatteryBroadcast, mStats, + SystemClock.elapsedRealtime() * 1000); + final View view = getView(); + info.bindHistory((UsageView) view.findViewById(R.id.battery_usage), mChargingParser, + mScreenOn, mGpsParser, mFlashlightParser, mCameraParser, mWifiParser, mCpuParser, + mPhoneParser); + ((TextView) view.findViewById(R.id.charge)).setText(info.batteryPercentString); + ((TextView) view.findViewById(R.id.estimation)).setText(info.remainingLabel); + + bindData(mChargingParser, R.string.battery_stats_charging_label, R.id.charging_group); + bindData(mScreenOn, R.string.battery_stats_screen_on_label, R.id.screen_on_group); + bindData(mGpsParser, R.string.battery_stats_gps_on_label, R.id.gps_group); + bindData(mFlashlightParser, R.string.battery_stats_flashlight_on_label, + R.id.flashlight_group); + bindData(mCameraParser, R.string.battery_stats_camera_on_label, R.id.camera_group); + bindData(mWifiParser, R.string.battery_stats_wifi_running_label, R.id.wifi_group); + bindData(mCpuParser, R.string.battery_stats_wake_lock_label, R.id.cpu_group); + bindData(mPhoneParser, R.string.battery_stats_phone_signal_label, R.id.cell_network_group); + } + + private void bindData(BatteryActiveProvider provider, int label, int groupId) { + View group = getView().findViewById(groupId); + group.setVisibility(provider.hasData() ? View.VISIBLE : View.GONE); + ((TextView) group.findViewById(android.R.id.title)).setText(label); + ((BatteryActiveView) group.findViewById(R.id.battery_active)).setProvider(provider); } @Override diff --git a/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java b/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java index 7aafebad79a..ba93f980afc 100644 --- a/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java +++ b/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java @@ -44,10 +44,11 @@ public class BatteryHistoryPreference extends Preference { public BatteryHistoryPreference(Context context, AttributeSet attrs) { super(context, attrs); setLayoutResource(R.layout.battery_usage_graph); + setSelectable(true); } @Override - protected void onClick() { + public void performClick() { mHelper.storeStatsHistoryInFile(BATTERY_HISTORY_FILE); Bundle args = new Bundle(); args.putString(BatteryHistoryDetail.EXTRA_STATS, BATTERY_HISTORY_FILE); @@ -66,9 +67,11 @@ public class BatteryHistoryPreference extends Preference { @Override public void onBindViewHolder(PreferenceViewHolder view) { + super.onBindViewHolder(view); if (mBatteryInfo == null) { return; } + view.itemView.setClickable(true); view.setDividerAllowedAbove(true); ((TextView) view.findViewById(R.id.charge)).setText(mBatteryInfo.batteryPercentString); ((TextView) view.findViewById(R.id.estimation)).setText(mBatteryInfo.remainingLabel); diff --git a/src/com/android/settings/fuelgauge/BatteryWifiParser.java b/src/com/android/settings/fuelgauge/BatteryWifiParser.java new file mode 100644 index 00000000000..014c069511f --- /dev/null +++ b/src/com/android/settings/fuelgauge/BatteryWifiParser.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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.android.settings.fuelgauge; + +import android.os.BatteryStats; +import android.os.BatteryStats.HistoryItem; + +public class BatteryWifiParser extends BatteryFlagParser { + + public BatteryWifiParser(int accentColor) { + super(accentColor, false, 0); + } + + @Override + protected boolean isSet(HistoryItem record) { + switch ((record.states2 & HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK) + >> HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT) { + case BatteryStats.WIFI_SUPPL_STATE_DISCONNECTED: + case BatteryStats.WIFI_SUPPL_STATE_DORMANT: + case BatteryStats.WIFI_SUPPL_STATE_INACTIVE: + case BatteryStats.WIFI_SUPPL_STATE_INTERFACE_DISABLED: + case BatteryStats.WIFI_SUPPL_STATE_INVALID: + case BatteryStats.WIFI_SUPPL_STATE_UNINITIALIZED: + return false; + } + return true; + } +} diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java index a0d276f20d6..bc44eeb6050 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java +++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java @@ -116,7 +116,7 @@ public class PowerUsageSummary extends PowerUsageBase { @Override public boolean onPreferenceTreeClick(Preference preference) { if (!(preference instanceof PowerGaugePreference)) { - return false; + return super.onPreferenceTreeClick(preference); } PowerGaugePreference pgp = (PowerGaugePreference) preference; BatteryEntry entry = pgp.getInfo();