Home | History | Annotate | Download | only in tiles
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.systemui.qs.tiles;
     17 
     18 import android.content.BroadcastReceiver;
     19 import android.content.Context;
     20 import android.content.Intent;
     21 import android.content.IntentFilter;
     22 import android.graphics.drawable.Drawable;
     23 import android.os.Handler;
     24 import android.os.Looper;
     25 import android.text.SpannableStringBuilder;
     26 import android.text.Spanned;
     27 import android.text.style.RelativeSizeSpan;
     28 import android.util.TypedValue;
     29 import android.view.LayoutInflater;
     30 import android.view.View;
     31 import android.view.View.OnAttachStateChangeListener;
     32 import android.view.View.OnClickListener;
     33 import android.view.ViewGroup;
     34 import android.widget.Button;
     35 import android.widget.Checkable;
     36 import android.widget.ImageView;
     37 import android.widget.TextView;
     38 import com.android.internal.logging.MetricsProto.MetricsEvent;
     39 import com.android.settingslib.BatteryInfo;
     40 import com.android.settingslib.graph.UsageView;
     41 import com.android.systemui.BatteryMeterDrawable;
     42 import com.android.systemui.R;
     43 import com.android.systemui.qs.QSTile;
     44 import com.android.systemui.statusbar.policy.BatteryController;
     45 
     46 import java.text.NumberFormat;
     47 
     48 public class BatteryTile extends QSTile<QSTile.State> implements BatteryController.BatteryStateChangeCallback {
     49 
     50     private final BatteryController mBatteryController;
     51     private final BatteryDetail mBatteryDetail = new BatteryDetail();
     52 
     53     private int mLevel;
     54     private boolean mPowerSave;
     55     private boolean mCharging;
     56     private boolean mDetailShown;
     57     private boolean mPluggedIn;
     58 
     59     public BatteryTile(Host host) {
     60         super(host);
     61         mBatteryController = host.getBatteryController();
     62     }
     63 
     64     @Override
     65     public State newTileState() {
     66         return new QSTile.State();
     67     }
     68 
     69     @Override
     70     public DetailAdapter getDetailAdapter() {
     71         return mBatteryDetail;
     72     }
     73 
     74     @Override
     75     public int getMetricsCategory() {
     76         return MetricsEvent.QS_BATTERY_TILE;
     77     }
     78 
     79     @Override
     80     public void setListening(boolean listening) {
     81         if (listening) {
     82             mBatteryController.addStateChangedCallback(this);
     83         } else {
     84             mBatteryController.removeStateChangedCallback(this);
     85         }
     86     }
     87 
     88     @Override
     89     public void setDetailListening(boolean listening) {
     90         super.setDetailListening(listening);
     91         if (!listening) {
     92             mBatteryDetail.mCurrentView = null;
     93         }
     94     }
     95 
     96     @Override
     97     public Intent getLongClickIntent() {
     98         return new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
     99     }
    100 
    101     @Override
    102     protected void handleClick() {
    103         showDetail(true);
    104     }
    105 
    106     @Override
    107     public CharSequence getTileLabel() {
    108         return mContext.getString(R.string.battery);
    109     }
    110 
    111     @Override
    112     protected void handleUpdateState(State state, Object arg) {
    113         int level = (arg != null) ? (Integer) arg : mLevel;
    114         String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
    115 
    116         state.icon = new Icon() {
    117             @Override
    118             public Drawable getDrawable(Context context) {
    119                 BatteryMeterDrawable drawable =
    120                         new BatteryMeterDrawable(context, new Handler(Looper.getMainLooper()),
    121                         context.getColor(R.color.batterymeter_frame_color));
    122                 drawable.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
    123                 drawable.onPowerSaveChanged(mPowerSave);
    124                 return drawable;
    125             }
    126 
    127             @Override
    128             public int getPadding() {
    129                 return mHost.getContext().getResources().getDimensionPixelSize(
    130                         R.dimen.qs_battery_padding);
    131             }
    132         };
    133         state.label = percentage;
    134         state.contentDescription = mContext.getString(R.string.accessibility_quick_settings_battery,
    135                 percentage) + "," +
    136                 (mPowerSave ? mContext.getString(R.string.battery_saver_notification_title)
    137                         : mCharging ? mContext.getString(R.string.expanded_header_battery_charging)
    138                                 : "")
    139                 + "," + mContext.getString(R.string.accessibility_battery_details);
    140         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
    141                 = Button.class.getName();
    142     }
    143 
    144     @Override
    145     public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
    146         mLevel = level;
    147         mPluggedIn = pluggedIn;
    148         mCharging = charging;
    149         refreshState((Integer) level);
    150         if (mDetailShown) {
    151             mBatteryDetail.postBindView();
    152         }
    153     }
    154 
    155     @Override
    156     public void onPowerSaveChanged(boolean isPowerSave) {
    157         mPowerSave = isPowerSave;
    158         refreshState(null);
    159         if (mDetailShown) {
    160             mBatteryDetail.postBindView();
    161         }
    162     }
    163 
    164     private final class BatteryDetail implements DetailAdapter, OnClickListener,
    165             OnAttachStateChangeListener {
    166         private final BatteryMeterDrawable mDrawable = new BatteryMeterDrawable(mHost.getContext(),
    167                 new Handler(), mHost.getContext().getColor(R.color.batterymeter_frame_color));
    168         private View mCurrentView;
    169 
    170         @Override
    171         public CharSequence getTitle() {
    172             return mContext.getString(R.string.battery_panel_title, mLevel);
    173         }
    174 
    175         @Override
    176         public Boolean getToggleState() {
    177             return null;
    178         }
    179 
    180         @Override
    181         public View createDetailView(Context context, View convertView, ViewGroup parent) {
    182             if (convertView == null) {
    183                 convertView = LayoutInflater.from(mContext).inflate(R.layout.battery_detail, parent,
    184                         false);
    185             }
    186             mCurrentView = convertView;
    187             mCurrentView.addOnAttachStateChangeListener(this);
    188             bindView();
    189             return convertView;
    190         }
    191 
    192         private void postBindView() {
    193             if (mCurrentView == null) return;
    194             mCurrentView.post(new Runnable() {
    195                 @Override
    196                 public void run() {
    197                     bindView();
    198                 }
    199             });
    200         }
    201 
    202         private void bindView() {
    203             if (mCurrentView == null) {
    204                 return;
    205             }
    206             mDrawable.onBatteryLevelChanged(100, false, false);
    207             mDrawable.onPowerSaveChanged(true);
    208             mDrawable.disableShowPercent();
    209             ((ImageView) mCurrentView.findViewById(android.R.id.icon)).setImageDrawable(mDrawable);
    210             Checkable checkbox = (Checkable) mCurrentView.findViewById(android.R.id.toggle);
    211             checkbox.setChecked(mPowerSave);
    212             BatteryInfo.getBatteryInfo(mContext, new BatteryInfo.Callback() {
    213                 @Override
    214                 public void onBatteryInfoLoaded(BatteryInfo info) {
    215                     if (mCurrentView != null) {
    216                         bindBatteryInfo(info);
    217                     }
    218                 }
    219             });
    220             final TextView batterySaverTitle =
    221                     (TextView) mCurrentView.findViewById(android.R.id.title);
    222             final TextView batterySaverSummary =
    223                     (TextView) mCurrentView.findViewById(android.R.id.summary);
    224             if (mCharging) {
    225                 mCurrentView.findViewById(R.id.switch_container).setAlpha(.7f);
    226                 batterySaverTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
    227                 batterySaverTitle.setText(R.string.battery_detail_charging_summary);
    228                 mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.GONE);
    229                 mCurrentView.findViewById(R.id.switch_container).setClickable(false);
    230             } else {
    231                 mCurrentView.findViewById(R.id.switch_container).setAlpha(1);
    232                 batterySaverTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
    233                 batterySaverTitle.setText(R.string.battery_detail_switch_title);
    234                 batterySaverSummary.setText(R.string.battery_detail_switch_summary);
    235                 mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.VISIBLE);
    236                 mCurrentView.findViewById(R.id.switch_container).setClickable(true);
    237                 mCurrentView.findViewById(R.id.switch_container).setOnClickListener(this);
    238             }
    239         }
    240 
    241         private void bindBatteryInfo(BatteryInfo info) {
    242             SpannableStringBuilder builder = new SpannableStringBuilder();
    243             builder.append(info.batteryPercentString, new RelativeSizeSpan(2.6f),
    244                     Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
    245             if (info.remainingLabel != null) {
    246                 if (mContext.getResources().getBoolean(R.bool.quick_settings_wide)) {
    247                     builder.append(' ');
    248                 } else {
    249                     builder.append('\n');
    250                 }
    251                 builder.append(info.remainingLabel);
    252             }
    253             ((TextView) mCurrentView.findViewById(R.id.charge_and_estimation)).setText(builder);
    254 
    255             info.bindHistory((UsageView) mCurrentView.findViewById(R.id.battery_usage));
    256         }
    257 
    258         @Override
    259         public void onClick(View v) {
    260             mBatteryController.setPowerSaveMode(!mPowerSave);
    261         }
    262 
    263         @Override
    264         public Intent getSettingsIntent() {
    265             return new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
    266         }
    267 
    268         @Override
    269         public void setToggleState(boolean state) {
    270             // No toggle state.
    271         }
    272 
    273         @Override
    274         public int getMetricsCategory() {
    275             return MetricsEvent.QS_BATTERY_DETAIL;
    276         }
    277 
    278         @Override
    279         public void onViewAttachedToWindow(View v) {
    280             if (!mDetailShown) {
    281                 mDetailShown = true;
    282                 v.getContext().registerReceiver(mReceiver,
    283                         new IntentFilter(Intent.ACTION_TIME_TICK));
    284             }
    285         }
    286 
    287         @Override
    288         public void onViewDetachedFromWindow(View v) {
    289             if (mDetailShown) {
    290                 mDetailShown = false;
    291                 v.getContext().unregisterReceiver(mReceiver);
    292             }
    293         }
    294 
    295         private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    296             @Override
    297             public void onReceive(Context context, Intent intent) {
    298                 postBindView();
    299             }
    300         };
    301     }
    302 }
    303