Loading core/java/com/android/internal/statusbar/IStatusBar.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ oneway interface IStatusBar void animateCollapsePanels(); void togglePanel(); void showChargingAnimation(int batteryLevel); /** * Notifies the status bar of a System UI visibility flag change. * Loading packages/SystemUI/res/layout/wireless_charging_layout.xml 0 → 100644 +56 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- /* ** Copyright 2018, 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. */ --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Circle animation --> <com.android.systemui.charging.WirelessChargingView android:id="@+id/wireless_charging_view" android:layout_width="match_parent" android:layout_height="match_parent" android:elevation="4dp"/> <!-- Text inside circle --> <LinearLayout android:id="@+id/wireless_charging_text_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:orientation="vertical"> <TextView android:id="@+id/wireless_charging_percentage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textSize="32sp" android:textColor="?attr/wallpaperTextColor"/> <TextView android:id="@+id/wireless_charging_secondary_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="?attr/wallpaperTextColor"/> </LinearLayout> </FrameLayout> No newline at end of file packages/SystemUI/res/values/dimens.xml +8 −0 Original line number Diff line number Diff line Loading @@ -895,4 +895,12 @@ <dimen name="fingerprint_dialog_icon_size">44dp</dimen> <dimen name="fingerprint_dialog_fp_icon_size">60dp</dimen> <dimen name="fingerprint_dialog_animation_translation_offset">350dp</dimen> <!-- WirelessCharging Animation values --> <!-- Starting text size of batteryLevel for wireless charging animation --> <dimen name="config_batteryLevelTextSizeStart" format="float">5.0</dimen> <!-- Ending text size of batteryLevel for wireless charging animation --> <dimen name="config_batteryLevelTextSizeEnd" format="float">32.0</dimen> <!-- Wireless Charging battery level text animation duration --> <integer name="config_batteryLevelTextAnimationDuration">400</integer> </resources> packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java 0 → 100644 +213 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.systemui.charging; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; import android.graphics.PixelFormat; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.util.Slog; import android.view.Gravity; import android.view.View; import android.view.WindowManager; /** * A WirelessChargingAnimation is a view containing view + animation for wireless charging. * @hide */ public class WirelessChargingAnimation { public static final long DURATION = 1400; private static final String TAG = "WirelessChargingView"; private static final boolean LOCAL_LOGV = false; private final WirelessChargingView mCurrentWirelessChargingView; private static WirelessChargingView mPreviousWirelessChargingView; /** * Constructs an empty WirelessChargingAnimation object. If looper is null, * Looper.myLooper() is used. Must set * {@link WirelessChargingAnimation#mCurrentWirelessChargingView} * before calling {@link #show} - can be done through {@link #makeWirelessChargingAnimation}. * @hide */ public WirelessChargingAnimation(@NonNull Context context, @Nullable Looper looper, int batteryLevel) { mCurrentWirelessChargingView = new WirelessChargingView(context, looper, batteryLevel); } /** * Creates a wireless charging animation object populated with next view. * @hide */ public static WirelessChargingAnimation makeWirelessChargingAnimation(@NonNull Context context, @Nullable Looper looper, int batteryLevel) { return new WirelessChargingAnimation(context, looper, batteryLevel); } /** * Show the view for the specified duration. */ public void show() { if (mCurrentWirelessChargingView == null || mCurrentWirelessChargingView.mNextView == null) { throw new RuntimeException("setView must have been called"); } if (mPreviousWirelessChargingView != null) { mPreviousWirelessChargingView.hide(0); } mPreviousWirelessChargingView = mCurrentWirelessChargingView; mCurrentWirelessChargingView.show(); mCurrentWirelessChargingView.hide(DURATION); } private static class WirelessChargingView { private static final int SHOW = 0; private static final int HIDE = 1; private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(); private final Handler mHandler; private int mGravity; private View mView; private View mNextView; private WindowManager mWM; public WirelessChargingView(Context context, @Nullable Looper looper, int batteryLevel) { mNextView = new WirelessChargingLayout(context, batteryLevel); mGravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER; final WindowManager.LayoutParams params = mParams; params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.format = PixelFormat.TRANSLUCENT; params.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; params.setTitle("Charging Animation"); params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_DIM_BEHIND; params.dimAmount = .3f; if (looper == null) { // Use Looper.myLooper() if looper is not specified. looper = Looper.myLooper(); if (looper == null) { throw new RuntimeException( "Can't display wireless animation on a thread that has not called " + "Looper.prepare()"); } } mHandler = new Handler(looper, null) { @Override public void handleMessage(Message msg) { switch (msg.what) { case SHOW: { handleShow(); break; } case HIDE: { handleHide(); // Don't do this in handleHide() because it is also invoked by // handleShow() mNextView = null; break; } } } }; } public void show() { if (LOCAL_LOGV) Log.v(TAG, "SHOW: " + this); mHandler.obtainMessage(SHOW).sendToTarget(); } public void hide(long duration) { if (LOCAL_LOGV) Log.v(TAG, "HIDE: " + this); mHandler.sendMessageDelayed(Message.obtain(mHandler, HIDE), duration); } private void handleShow() { if (LOCAL_LOGV) { Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView + " mNextView=" + mNextView); } if (mView != mNextView) { // remove the old view if necessary handleHide(); mView = mNextView; Context context = mView.getContext().getApplicationContext(); String packageName = mView.getContext().getOpPackageName(); if (context == null) { context = mView.getContext(); } mWM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); // We can resolve the Gravity here by using the Locale for getting // the layout direction final Configuration config = mView.getContext().getResources().getConfiguration(); final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection()); mParams.gravity = gravity; if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) { mParams.horizontalWeight = 1.0f; } if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) { mParams.verticalWeight = 1.0f; } mParams.packageName = packageName; mParams.hideTimeoutMilliseconds = DURATION; if (mView.getParent() != null) { if (LOCAL_LOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this); mWM.removeView(mView); } if (LOCAL_LOGV) Log.v(TAG, "ADD! " + mView + " in " + this); try { mWM.addView(mView, mParams); } catch (WindowManager.BadTokenException e) { Slog.d(TAG, "Unable to add wireless charging view. " + e); } } } private void handleHide() { if (LOCAL_LOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView); if (mView != null) { if (mView.getParent() != null) { if (LOCAL_LOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this); mWM.removeViewImmediate(mView); } mView = null; } } } } packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java 0 → 100644 +81 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.systemui.charging; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; import android.util.AttributeSet; import android.widget.FrameLayout; import android.widget.TextView; import com.android.systemui.R; import java.text.NumberFormat; /** * @hide */ public class WirelessChargingLayout extends FrameLayout { private final static int UNKNOWN_BATTERY_LEVEL = -1; public WirelessChargingLayout(Context context) { super(context); init(context, null); } public WirelessChargingLayout(Context context, int batterylLevel) { super(context); init(context, null, batterylLevel); } public WirelessChargingLayout(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } private void init(Context c, AttributeSet attrs) { init(c, attrs, -1); } private void init(Context c, AttributeSet attrs, int batteryLevel) { final int mBatteryLevel = batteryLevel; inflate(c, R.layout.wireless_charging_layout, this); // where the circle animation occurs: final WirelessChargingView mChargingView = findViewById(R.id.wireless_charging_view); // amount of battery: final TextView mPercentage = findViewById(R.id.wireless_charging_percentage); // (optional) time until full charge if available final TextView mSecondaryText = findViewById(R.id.wireless_charging_secondary_text); if (batteryLevel != UNKNOWN_BATTERY_LEVEL) { mPercentage.setText(NumberFormat.getPercentInstance().format(mBatteryLevel / 100f)); ValueAnimator animator = ObjectAnimator.ofFloat(mPercentage, "textSize", getContext().getResources().getFloat(R.dimen.config_batteryLevelTextSizeStart), getContext().getResources().getFloat(R.dimen.config_batteryLevelTextSizeEnd)); animator.setDuration((long) getContext().getResources().getInteger( R.integer.config_batteryLevelTextAnimationDuration)); animator.start(); } } } Loading
core/java/com/android/internal/statusbar/IStatusBar.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ oneway interface IStatusBar void animateCollapsePanels(); void togglePanel(); void showChargingAnimation(int batteryLevel); /** * Notifies the status bar of a System UI visibility flag change. * Loading
packages/SystemUI/res/layout/wireless_charging_layout.xml 0 → 100644 +56 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- /* ** Copyright 2018, 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. */ --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Circle animation --> <com.android.systemui.charging.WirelessChargingView android:id="@+id/wireless_charging_view" android:layout_width="match_parent" android:layout_height="match_parent" android:elevation="4dp"/> <!-- Text inside circle --> <LinearLayout android:id="@+id/wireless_charging_text_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:orientation="vertical"> <TextView android:id="@+id/wireless_charging_percentage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textSize="32sp" android:textColor="?attr/wallpaperTextColor"/> <TextView android:id="@+id/wireless_charging_secondary_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="?attr/wallpaperTextColor"/> </LinearLayout> </FrameLayout> No newline at end of file
packages/SystemUI/res/values/dimens.xml +8 −0 Original line number Diff line number Diff line Loading @@ -895,4 +895,12 @@ <dimen name="fingerprint_dialog_icon_size">44dp</dimen> <dimen name="fingerprint_dialog_fp_icon_size">60dp</dimen> <dimen name="fingerprint_dialog_animation_translation_offset">350dp</dimen> <!-- WirelessCharging Animation values --> <!-- Starting text size of batteryLevel for wireless charging animation --> <dimen name="config_batteryLevelTextSizeStart" format="float">5.0</dimen> <!-- Ending text size of batteryLevel for wireless charging animation --> <dimen name="config_batteryLevelTextSizeEnd" format="float">32.0</dimen> <!-- Wireless Charging battery level text animation duration --> <integer name="config_batteryLevelTextAnimationDuration">400</integer> </resources>
packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java 0 → 100644 +213 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.systemui.charging; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; import android.graphics.PixelFormat; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.util.Slog; import android.view.Gravity; import android.view.View; import android.view.WindowManager; /** * A WirelessChargingAnimation is a view containing view + animation for wireless charging. * @hide */ public class WirelessChargingAnimation { public static final long DURATION = 1400; private static final String TAG = "WirelessChargingView"; private static final boolean LOCAL_LOGV = false; private final WirelessChargingView mCurrentWirelessChargingView; private static WirelessChargingView mPreviousWirelessChargingView; /** * Constructs an empty WirelessChargingAnimation object. If looper is null, * Looper.myLooper() is used. Must set * {@link WirelessChargingAnimation#mCurrentWirelessChargingView} * before calling {@link #show} - can be done through {@link #makeWirelessChargingAnimation}. * @hide */ public WirelessChargingAnimation(@NonNull Context context, @Nullable Looper looper, int batteryLevel) { mCurrentWirelessChargingView = new WirelessChargingView(context, looper, batteryLevel); } /** * Creates a wireless charging animation object populated with next view. * @hide */ public static WirelessChargingAnimation makeWirelessChargingAnimation(@NonNull Context context, @Nullable Looper looper, int batteryLevel) { return new WirelessChargingAnimation(context, looper, batteryLevel); } /** * Show the view for the specified duration. */ public void show() { if (mCurrentWirelessChargingView == null || mCurrentWirelessChargingView.mNextView == null) { throw new RuntimeException("setView must have been called"); } if (mPreviousWirelessChargingView != null) { mPreviousWirelessChargingView.hide(0); } mPreviousWirelessChargingView = mCurrentWirelessChargingView; mCurrentWirelessChargingView.show(); mCurrentWirelessChargingView.hide(DURATION); } private static class WirelessChargingView { private static final int SHOW = 0; private static final int HIDE = 1; private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(); private final Handler mHandler; private int mGravity; private View mView; private View mNextView; private WindowManager mWM; public WirelessChargingView(Context context, @Nullable Looper looper, int batteryLevel) { mNextView = new WirelessChargingLayout(context, batteryLevel); mGravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER; final WindowManager.LayoutParams params = mParams; params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.format = PixelFormat.TRANSLUCENT; params.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; params.setTitle("Charging Animation"); params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_DIM_BEHIND; params.dimAmount = .3f; if (looper == null) { // Use Looper.myLooper() if looper is not specified. looper = Looper.myLooper(); if (looper == null) { throw new RuntimeException( "Can't display wireless animation on a thread that has not called " + "Looper.prepare()"); } } mHandler = new Handler(looper, null) { @Override public void handleMessage(Message msg) { switch (msg.what) { case SHOW: { handleShow(); break; } case HIDE: { handleHide(); // Don't do this in handleHide() because it is also invoked by // handleShow() mNextView = null; break; } } } }; } public void show() { if (LOCAL_LOGV) Log.v(TAG, "SHOW: " + this); mHandler.obtainMessage(SHOW).sendToTarget(); } public void hide(long duration) { if (LOCAL_LOGV) Log.v(TAG, "HIDE: " + this); mHandler.sendMessageDelayed(Message.obtain(mHandler, HIDE), duration); } private void handleShow() { if (LOCAL_LOGV) { Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView + " mNextView=" + mNextView); } if (mView != mNextView) { // remove the old view if necessary handleHide(); mView = mNextView; Context context = mView.getContext().getApplicationContext(); String packageName = mView.getContext().getOpPackageName(); if (context == null) { context = mView.getContext(); } mWM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); // We can resolve the Gravity here by using the Locale for getting // the layout direction final Configuration config = mView.getContext().getResources().getConfiguration(); final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection()); mParams.gravity = gravity; if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) { mParams.horizontalWeight = 1.0f; } if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) { mParams.verticalWeight = 1.0f; } mParams.packageName = packageName; mParams.hideTimeoutMilliseconds = DURATION; if (mView.getParent() != null) { if (LOCAL_LOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this); mWM.removeView(mView); } if (LOCAL_LOGV) Log.v(TAG, "ADD! " + mView + " in " + this); try { mWM.addView(mView, mParams); } catch (WindowManager.BadTokenException e) { Slog.d(TAG, "Unable to add wireless charging view. " + e); } } } private void handleHide() { if (LOCAL_LOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView); if (mView != null) { if (mView.getParent() != null) { if (LOCAL_LOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this); mWM.removeViewImmediate(mView); } mView = null; } } } }
packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java 0 → 100644 +81 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.systemui.charging; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; import android.util.AttributeSet; import android.widget.FrameLayout; import android.widget.TextView; import com.android.systemui.R; import java.text.NumberFormat; /** * @hide */ public class WirelessChargingLayout extends FrameLayout { private final static int UNKNOWN_BATTERY_LEVEL = -1; public WirelessChargingLayout(Context context) { super(context); init(context, null); } public WirelessChargingLayout(Context context, int batterylLevel) { super(context); init(context, null, batterylLevel); } public WirelessChargingLayout(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } private void init(Context c, AttributeSet attrs) { init(c, attrs, -1); } private void init(Context c, AttributeSet attrs, int batteryLevel) { final int mBatteryLevel = batteryLevel; inflate(c, R.layout.wireless_charging_layout, this); // where the circle animation occurs: final WirelessChargingView mChargingView = findViewById(R.id.wireless_charging_view); // amount of battery: final TextView mPercentage = findViewById(R.id.wireless_charging_percentage); // (optional) time until full charge if available final TextView mSecondaryText = findViewById(R.id.wireless_charging_secondary_text); if (batteryLevel != UNKNOWN_BATTERY_LEVEL) { mPercentage.setText(NumberFormat.getPercentInstance().format(mBatteryLevel / 100f)); ValueAnimator animator = ObjectAnimator.ofFloat(mPercentage, "textSize", getContext().getResources().getFloat(R.dimen.config_batteryLevelTextSizeStart), getContext().getResources().getFloat(R.dimen.config_batteryLevelTextSizeEnd)); animator.setDuration((long) getContext().getResources().getInteger( R.integer.config_batteryLevelTextAnimationDuration)); animator.start(); } } }