| /* |
| * Copyright (C) 2017 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.statusbar.phone; |
| |
| import static android.app.StatusBarManager.DISABLE_CLOCK; |
| import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS; |
| import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO; |
| |
| import android.annotation.Nullable; |
| import android.app.Fragment; |
| import android.os.Bundle; |
| import android.os.Parcelable; |
| import android.util.SparseArray; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.ViewStub; |
| import android.widget.LinearLayout; |
| |
| import com.android.systemui.Dependency; |
| import com.android.systemui.Interpolators; |
| import com.android.systemui.R; |
| import com.android.systemui.SysUiServiceProvider; |
| import com.android.systemui.statusbar.CommandQueue; |
| import com.android.systemui.statusbar.StatusBarStateController; |
| import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager; |
| import com.android.systemui.statusbar.policy.EncryptionHelper; |
| import com.android.systemui.statusbar.policy.KeyguardMonitor; |
| import com.android.systemui.statusbar.policy.NetworkController; |
| import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; |
| |
| /** |
| * Contains the collapsed status bar and handles hiding/showing based on disable flags |
| * and keyguard state. Also manages lifecycle to make sure the views it contains are being |
| * updated by the StatusBarIconController and DarkIconManager while it is attached. |
| */ |
| public class CollapsedStatusBarFragment extends Fragment implements CommandQueue.Callbacks { |
| |
| public static final String TAG = "CollapsedStatusBarFragment"; |
| private static final String EXTRA_PANEL_STATE = "panel_state"; |
| public static final String STATUS_BAR_ICON_MANAGER_TAG = "status_bar_icon_manager"; |
| public static final int FADE_IN_DURATION = 320; |
| public static final int FADE_IN_DELAY = 50; |
| private PhoneStatusBarView mStatusBar; |
| private StatusBarStateController mStatusBarStateController; |
| private KeyguardMonitor mKeyguardMonitor; |
| private NetworkController mNetworkController; |
| private LinearLayout mSystemIconArea; |
| private View mClockView; |
| private View mNotificationIconAreaInner; |
| private int mDisabled1; |
| private StatusBar mStatusBarComponent; |
| private DarkIconManager mDarkIconManager; |
| private View mOperatorNameFrame; |
| private CommandQueue mCommandQueue; |
| |
| private SignalCallback mSignalCallback = new SignalCallback() { |
| @Override |
| public void setIsAirplaneMode(NetworkController.IconState icon) { |
| mCommandQueue.recomputeDisableFlags(true /* animate */); |
| } |
| }; |
| |
| @Override |
| public void onCreate(@Nullable Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| mKeyguardMonitor = Dependency.get(KeyguardMonitor.class); |
| mNetworkController = Dependency.get(NetworkController.class); |
| mStatusBarStateController = Dependency.get(StatusBarStateController.class); |
| mStatusBarComponent = SysUiServiceProvider.getComponent(getContext(), StatusBar.class); |
| mCommandQueue = SysUiServiceProvider.getComponent(getContext(), CommandQueue.class); |
| } |
| |
| @Override |
| public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, |
| Bundle savedInstanceState) { |
| return inflater.inflate(R.layout.status_bar, container, false); |
| } |
| |
| @Override |
| public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { |
| super.onViewCreated(view, savedInstanceState); |
| mStatusBar = (PhoneStatusBarView) view; |
| if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_PANEL_STATE)) { |
| mStatusBar.restoreHierarchyState( |
| savedInstanceState.getSparseParcelableArray(EXTRA_PANEL_STATE)); |
| } |
| mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons)); |
| mDarkIconManager.setShouldLog(true); |
| Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager); |
| mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area); |
| mClockView = mStatusBar.findViewById(R.id.clock); |
| showSystemIconArea(false); |
| showClock(false); |
| initEmergencyCryptkeeperText(); |
| initOperatorName(); |
| } |
| |
| @Override |
| public void onSaveInstanceState(Bundle outState) { |
| super.onSaveInstanceState(outState); |
| SparseArray<Parcelable> states = new SparseArray<>(); |
| mStatusBar.saveHierarchyState(states); |
| outState.putSparseParcelableArray(EXTRA_PANEL_STATE, states); |
| } |
| |
| @Override |
| public void onResume() { |
| super.onResume(); |
| mCommandQueue.addCallbacks(this); |
| } |
| |
| @Override |
| public void onPause() { |
| super.onPause(); |
| mCommandQueue.removeCallbacks(this); |
| } |
| |
| @Override |
| public void onDestroyView() { |
| super.onDestroyView(); |
| Dependency.get(StatusBarIconController.class).removeIconGroup(mDarkIconManager); |
| if (mNetworkController.hasEmergencyCryptKeeperText()) { |
| mNetworkController.removeCallback(mSignalCallback); |
| } |
| } |
| |
| public void initNotificationIconArea(NotificationIconAreaController |
| notificationIconAreaController) { |
| ViewGroup notificationIconArea = mStatusBar.findViewById(R.id.notification_icon_area); |
| mNotificationIconAreaInner = |
| notificationIconAreaController.getNotificationInnerAreaView(); |
| if (mNotificationIconAreaInner.getParent() != null) { |
| ((ViewGroup) mNotificationIconAreaInner.getParent()) |
| .removeView(mNotificationIconAreaInner); |
| } |
| notificationIconArea.addView(mNotificationIconAreaInner); |
| // Default to showing until we know otherwise. |
| showNotificationIconArea(false); |
| } |
| |
| @Override |
| public void disable(int state1, int state2, boolean animate) { |
| state1 = adjustDisableFlags(state1); |
| final int old1 = mDisabled1; |
| final int diff1 = state1 ^ old1; |
| mDisabled1 = state1; |
| if ((diff1 & DISABLE_SYSTEM_INFO) != 0) { |
| if ((state1 & DISABLE_SYSTEM_INFO) != 0) { |
| hideSystemIconArea(animate); |
| hideOperatorName(animate); |
| } else { |
| showSystemIconArea(animate); |
| showOperatorName(animate); |
| } |
| } |
| if ((diff1 & DISABLE_NOTIFICATION_ICONS) != 0) { |
| if ((state1 & DISABLE_NOTIFICATION_ICONS) != 0) { |
| hideNotificationIconArea(animate); |
| } else { |
| showNotificationIconArea(animate); |
| } |
| } |
| // The clock may have already been hidden, but we might want to shift its |
| // visibility to GONE from INVISIBLE or vice versa |
| if ((diff1 & DISABLE_CLOCK) != 0 || mClockView.getVisibility() != clockHiddenMode()) { |
| if ((state1 & DISABLE_CLOCK) != 0) { |
| hideClock(animate); |
| } else { |
| showClock(animate); |
| } |
| } |
| } |
| |
| protected int adjustDisableFlags(int state) { |
| if (!mStatusBarComponent.isLaunchTransitionFadingAway() |
| && !mKeyguardMonitor.isKeyguardFadingAway() |
| && shouldHideNotificationIcons()) { |
| state |= DISABLE_NOTIFICATION_ICONS; |
| state |= DISABLE_SYSTEM_INFO; |
| state |= DISABLE_CLOCK; |
| } |
| |
| // In landscape, the heads up show but shouldHideNotificationIcons() return false |
| // because the visual icon is in notification icon area rather than heads up's space. |
| // whether the notification icon show or not, clock should hide when heads up show. |
| if (mStatusBarComponent.isHeadsUpShouldBeVisible()) { |
| state |= DISABLE_CLOCK; |
| } |
| |
| if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) { |
| if (mNetworkController.hasEmergencyCryptKeeperText()) { |
| state |= DISABLE_NOTIFICATION_ICONS; |
| } |
| if (!mNetworkController.isRadioOn()) { |
| state |= DISABLE_SYSTEM_INFO; |
| } |
| } |
| |
| if (mStatusBarStateController.isDozing()) { |
| state |= DISABLE_CLOCK | DISABLE_SYSTEM_INFO; |
| state &= ~DISABLE_NOTIFICATION_ICONS; |
| } |
| |
| return state; |
| } |
| |
| private boolean shouldHideNotificationIcons() { |
| if (!mStatusBar.isClosed() && mStatusBarComponent.hideStatusBarIconsWhenExpanded()) { |
| return true; |
| } |
| if (mStatusBarComponent.hideStatusBarIconsForBouncer()) { |
| return true; |
| } |
| return false; |
| } |
| |
| public void hideSystemIconArea(boolean animate) { |
| animateHide(mSystemIconArea, animate); |
| } |
| |
| public void showSystemIconArea(boolean animate) { |
| animateShow(mSystemIconArea, animate); |
| } |
| |
| public void hideClock(boolean animate) { |
| animateHiddenState(mClockView, clockHiddenMode(), animate); |
| } |
| |
| public void showClock(boolean animate) { |
| animateShow(mClockView, animate); |
| } |
| |
| /** |
| * If panel is expanded/expanding it usually means QS shade is opening, so |
| * don't set the clock GONE otherwise it'll mess up the animation. |
| */ |
| private int clockHiddenMode() { |
| if (!mStatusBar.isClosed() && !mKeyguardMonitor.isShowing() |
| && !mStatusBarStateController.isDozing()) { |
| return View.INVISIBLE; |
| } |
| return View.GONE; |
| } |
| |
| public void hideNotificationIconArea(boolean animate) { |
| animateHide(mNotificationIconAreaInner, animate); |
| } |
| |
| public void showNotificationIconArea(boolean animate) { |
| animateShow(mNotificationIconAreaInner, animate); |
| } |
| |
| public void hideOperatorName(boolean animate) { |
| if (mOperatorNameFrame != null) { |
| animateHide(mOperatorNameFrame, animate); |
| } |
| } |
| |
| public void showOperatorName(boolean animate) { |
| if (mOperatorNameFrame != null) { |
| animateShow(mOperatorNameFrame, animate); |
| } |
| } |
| |
| /** |
| * Animate a view to INVISIBLE or GONE |
| */ |
| private void animateHiddenState(final View v, int state, boolean animate) { |
| v.animate().cancel(); |
| if (!animate) { |
| v.setAlpha(0f); |
| v.setVisibility(state); |
| return; |
| } |
| |
| v.animate() |
| .alpha(0f) |
| .setDuration(160) |
| .setStartDelay(0) |
| .setInterpolator(Interpolators.ALPHA_OUT) |
| .withEndAction(() -> v.setVisibility(state)); |
| } |
| |
| /** |
| * Hides a view. |
| */ |
| private void animateHide(final View v, boolean animate) { |
| animateHiddenState(v, View.INVISIBLE, animate); |
| } |
| |
| /** |
| * Shows a view, and synchronizes the animation with Keyguard exit animations, if applicable. |
| */ |
| private void animateShow(View v, boolean animate) { |
| v.animate().cancel(); |
| v.setVisibility(View.VISIBLE); |
| if (!animate) { |
| v.setAlpha(1f); |
| return; |
| } |
| v.animate() |
| .alpha(1f) |
| .setDuration(FADE_IN_DURATION) |
| .setInterpolator(Interpolators.ALPHA_IN) |
| .setStartDelay(FADE_IN_DELAY) |
| |
| // We need to clean up any pending end action from animateHide if we call |
| // both hide and show in the same frame before the animation actually gets started. |
| // cancel() doesn't really remove the end action. |
| .withEndAction(null); |
| |
| // Synchronize the motion with the Keyguard fading if necessary. |
| if (mKeyguardMonitor.isKeyguardFadingAway()) { |
| v.animate() |
| .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration()) |
| .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN) |
| .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay()) |
| .start(); |
| } |
| } |
| |
| private void initEmergencyCryptkeeperText() { |
| View emergencyViewStub = mStatusBar.findViewById(R.id.emergency_cryptkeeper_text); |
| if (mNetworkController.hasEmergencyCryptKeeperText()) { |
| if (emergencyViewStub != null) { |
| ((ViewStub) emergencyViewStub).inflate(); |
| } |
| mNetworkController.addCallback(mSignalCallback); |
| } else if (emergencyViewStub != null) { |
| ViewGroup parent = (ViewGroup) emergencyViewStub.getParent(); |
| parent.removeView(emergencyViewStub); |
| } |
| } |
| |
| private void initOperatorName() { |
| if (getResources().getBoolean(R.bool.config_showOperatorNameInStatusBar)) { |
| ViewStub stub = mStatusBar.findViewById(R.id.operator_name); |
| mOperatorNameFrame = stub.inflate(); |
| } |
| } |
| } |