package tk.wasdennnoch.androidn_ify.systemui.qs.tiles; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.os.Handler; import android.os.Looper; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.RelativeSizeSpan; import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Checkable; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Switch; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; import tk.wasdennnoch.androidn_ify.R; import tk.wasdennnoch.androidn_ify.XposedHook; import tk.wasdennnoch.androidn_ify.extracted.settingslib.BatteryInfo; import tk.wasdennnoch.androidn_ify.extracted.settingslib.UsageView; import tk.wasdennnoch.androidn_ify.extracted.systemui.ResizingSpace; import tk.wasdennnoch.androidn_ify.systemui.SystemUIHooks; import tk.wasdennnoch.androidn_ify.systemui.notifications.StatusBarHeaderHooks; import tk.wasdennnoch.androidn_ify.systemui.qs.DetailViewManager; import tk.wasdennnoch.androidn_ify.systemui.qs.TilesManager; import tk.wasdennnoch.androidn_ify.systemui.qs.tiles.misc.BatteryInfoManager; import tk.wasdennnoch.androidn_ify.systemui.qs.tiles.misc.BatteryMeterDrawable; import tk.wasdennnoch.androidn_ify.utils.ConfigUtils; import tk.wasdennnoch.androidn_ify.utils.ResourceUtils; public class BatteryTile extends QSTile implements BatteryInfoManager.BatteryStatusListener { public static final String TILE_SPEC = "battery"; private BatteryInfoManager.BatteryData mTileBatteryData; private BatteryView mBatteryView; private final BatteryDetail mDetail = new BatteryDetail(); private final Object mBatteryDetail = DetailViewManager.getInstance().createProxy(mDetail); private boolean mListening; private boolean mDetailShown; public BatteryTile(TilesManager tilesManager, Object host, String key) { super(tilesManager, host, key); SystemUIHooks.batteryInfoManager.registerListener(this); } @Override public void handleUpdateState(Object state, Object arg) { mState.label = mResUtils.getString(R.string.battery); if (mTileBatteryData != null) { mState.label = mTileBatteryData.level + "%"; } if (mBatteryView != null) { mBatteryView.postInvalidate(); } super.handleUpdateState(state, arg); } @SuppressWarnings("deprecation") private BatteryMeterDrawable newDrawable() { return new BatteryMeterDrawable(mContext, new Handler(Looper.getMainLooper()), mContext.getResources().getColor(mContext.getResources().getIdentifier("batterymeter_frame_color", "color", XposedHook.PACKAGE_SYSTEMUI))); } @Override public View onCreateIcon() { FrameLayout iconFrame = new FrameLayout(mContext); FrameLayout.LayoutParams batteryLp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); batteryLp.gravity = Gravity.CENTER; mBatteryView = new BatteryView(mContext); mBatteryView.setLayoutParams(batteryLp); iconFrame.addView(mBatteryView); return iconFrame; } @Override public void onBatteryStatusChanged(BatteryInfoManager.BatteryData batteryData) { mTileBatteryData = batteryData; if (mListening) refreshState(); if (mDetailShown) mDetail.postBindView(); } @Override public void handleClick() { showDetail(true); } @Override public void handleLongClick() { startActivityDismissingKeyguard(Intent.ACTION_POWER_USAGE_SUMMARY); } @Override public Object getDetailAdapter() { return mBatteryDetail; } @Override public void setListening(boolean listening) { if (mListening == listening) return; mListening = listening; if (mListening) { SystemUIHooks.batteryInfoManager.registerListener(this); SystemUIHooks.batteryInfoManager.registerListener(mBatteryView); } else { SystemUIHooks.batteryInfoManager.unregisterListener(this); SystemUIHooks.batteryInfoManager.unregisterListener(mBatteryView); } } @Override public void handleDestroy() { SystemUIHooks.batteryInfoManager.unregisterListener(this); SystemUIHooks.batteryInfoManager.unregisterListener(mBatteryView); mTileBatteryData = null; mBatteryView = null; super.handleDestroy(); } // A mix of GB BatteryView and AOSP BatteryMeterView public class BatteryView extends ImageView implements BatteryInfoManager.BatteryStatusListener { private final BatteryMeterDrawable mDrawable = newDrawable(); public BatteryView(Context context) { super(context); mDrawable.setHasIntrinsicSize(false); mDrawable.setShowPercent(ConfigUtils.qs().battery_tile_show_percentage); setImageDrawable(mDrawable); int padding = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics())); setPadding(0, padding, 0, padding); SystemUIHooks.batteryInfoManager.registerListener(this); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final Resources res = getResources(); int width = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 13, res.getDisplayMetrics())); setMeasuredDimension(width, MeasureSpec.getSize(heightMeasureSpec)); } @Override public void onBatteryStatusChanged(BatteryInfoManager.BatteryData batteryData) { mDrawable.onBatteryStatusChanged(batteryData); } public void setShowPercent(boolean show) { mDrawable.setShowPercent(show); } } private final class BatteryDetail implements DetailViewManager.DetailAdapter, View.OnClickListener, View.OnAttachStateChangeListener, DetailViewManager.DetailViewAdapter { private final BatteryMeterDrawable mDrawable = newDrawable(); private View mCurrentView; @Override public int getTitle() { return StatusBarHeaderHooks.R_string_battery_panel_title; } @Override public Boolean getToggleState() { return null; } @Override public DetailViewManager.DetailViewAdapter createDetailView(Context context, View convertView, ViewGroup parent) { if (convertView == null || !(convertView instanceof DetailViewManager.DetailFrameLayout)) { DetailViewManager.DetailFrameLayout frameLayout = new DetailViewManager.DetailFrameLayout(context, this); ResourceUtils res = ResourceUtils.getInstance(context); LinearLayout layout = (LinearLayout) LayoutInflater.from(ResourceUtils.createOwnContext(mContext)).inflate(R.layout.battery_detail, parent, false); layout.addView(new ResizingSpace(context, 0, R.dimen.battery_detail_graph_space_top), 1); LinearLayout.LayoutParams usageViewLp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, res.getDimensionPixelSize(R.dimen.battery_usage_height)); usageViewLp.setMarginStart(res.getDimensionPixelSize(R.dimen.battery_usage_margin_start)); usageViewLp.setMarginEnd(res.getDimensionPixelSize(R.dimen.battery_usage_margin_end)); //noinspection deprecation UsageView usageView = new UsageView(context, 0x66FFFFFF, context.getResources().getColor(context.getResources().getIdentifier("system_accent_color", "color", XposedHook.PACKAGE_SYSTEMUI))); usageView.setId(R.id.battery_usage); usageView.setLayoutParams(usageViewLp); usageView.setSideLabels(res.getResources().getTextArray(R.array.battery_labels)); layout.addView(usageView, 2); layout.addView(new ResizingSpace(context, 0, R.dimen.battery_detail_graph_space_bottom), 3); frameLayout.addView(layout); convertView = frameLayout; } mCurrentView = convertView; mCurrentView.addOnAttachStateChangeListener(this); bindView(); return (DetailViewManager.DetailViewAdapter) convertView; } private void postBindView() { if (mCurrentView == null) return; mCurrentView.post(new Runnable() { @Override public void run() { bindView(); } }); } private void bindView() { if (mCurrentView == null) { return; } mDrawable.onBatteryLevelChanged(100, false); mDrawable.onPowerSaveChanged(true); mDrawable.disableShowPercent(); ((ImageView) mCurrentView.findViewById(android.R.id.icon)).setImageDrawable(mDrawable); Checkable checkbox = (Checkable) mCurrentView.findViewById(android.R.id.toggle); checkbox.setChecked(SystemUIHooks.batteryInfoManager.isPowerSaveMode()); BatteryInfo.getBatteryInfo(mContext, new BatteryInfo.Callback() { @Override public void onBatteryInfoLoaded(BatteryInfo info) { if (mCurrentView != null) { bindBatteryInfo(info); } } }); final TextView batterySaverTitle = (TextView) mCurrentView.findViewById(android.R.id.title); final TextView batterySaverSummary = (TextView) mCurrentView.findViewById(android.R.id.summary); if (mTileBatteryData.charging) { mCurrentView.findViewById(R.id.switch_container).setAlpha(.7f); batterySaverTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); batterySaverTitle.setText(mResUtils.getString(R.string.battery_detail_charging_summary)); mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.GONE); mCurrentView.findViewById(R.id.switch_container).setClickable(false); } else { mCurrentView.findViewById(R.id.switch_container).setAlpha(1); batterySaverTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); batterySaverTitle.setText(mResUtils.getString(R.string.battery_detail_switch_title)); batterySaverSummary.setText(mResUtils.getString(R.string.battery_detail_switch_summary)); mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.VISIBLE); mCurrentView.findViewById(R.id.switch_container).setClickable(true); mCurrentView.findViewById(R.id.switch_container).setOnClickListener(this); } } private void bindBatteryInfo(BatteryInfo info) { SpannableStringBuilder builder = new SpannableStringBuilder(); builder.append(info.batteryPercentString, new RelativeSizeSpan(2.6f), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); if (info.remainingLabel != null) { if (mResUtils.getResources().getBoolean(R.bool.quick_settings_wide)) { builder.append(' '); } else { builder.append('\n'); } builder.append(info.remainingLabel); } ((TextView) mCurrentView.findViewById(R.id.charge_and_estimation)).setText(builder); info.bindHistory((UsageView) mCurrentView.findViewById(R.id.battery_usage)); } @Override public void onClick(View v) { SystemUIHooks.batteryInfoManager.togglePowerSaving(); ((Switch) mCurrentView.findViewById(android.R.id.toggle)).setChecked(SystemUIHooks.batteryInfoManager.isPowerSaveMode()); } @Override public Intent getSettingsIntent() { return new Intent(Intent.ACTION_POWER_USAGE_SUMMARY); } @Override public void setToggleState(boolean state) { // No toggle state. } @Override public int getMetricsCategory() { return MetricsLogger.QS_INTENT; } @Override public boolean hasRightButton() { return false; } @Override public int getRightButtonResId() { return 0; } @Override public void handleRightButtonClick() { } @Override public void onViewAttachedToWindow(View v) { if (!mDetailShown) { mDetailShown = true; v.getContext().registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_TIME_TICK)); } } @Override public void onViewDetachedFromWindow(View v) { if (mDetailShown) { mDetailShown = false; v.getContext().unregisterReceiver(mReceiver); } } private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { postBindView(); } }; } }