StatusBarKeyguardViewManager.java revision 8c8bcc160aba9a5e93c8df2a99a39a856fafffab
15cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi/*
25cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi * Copyright (C) 2014 The Android Open Source Project
35cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi *
45cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License");
55cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi * you may not use this file except in compliance with the License.
65cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi * You may obtain a copy of the License at
75cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi *
85cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi *      http://www.apache.org/licenses/LICENSE-2.0
95cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi *
105cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi * Unless required by applicable law or agreed to in writing, software
115cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS,
125cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi * See the License for the specific language governing permissions and
145cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi * limitations under the License
155cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi */
165cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
175cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggipackage com.android.systemui.statusbar.phone;
185cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
195cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport android.content.Context;
205cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport android.os.Bundle;
215cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport android.os.IBinder;
225cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport android.os.RemoteException;
235cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport android.util.Log;
245cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport android.util.Slog;
255cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport android.view.LayoutInflater;
265cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport android.view.View;
275cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport android.view.ViewGroup;
285cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport android.view.ViewTreeObserver;
295cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
305cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport com.android.internal.policy.IKeyguardShowCallback;
315cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport com.android.internal.widget.LockPatternUtils;
3213b67a9cd5c84c586d71f81873191fe2d00d9cd2Jorim Jaggiimport com.android.keyguard.KeyguardHostView;
335cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport com.android.keyguard.KeyguardSimpleHostView;
345cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport com.android.keyguard.R;
355cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport com.android.keyguard.ViewMediatorCallback;
365cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggiimport com.android.systemui.keyguard.KeyguardViewMediator;
375cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
385cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi/**
395cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
405cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done,
415cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi * which is in turn, reported to this class by the current
425cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi * {@link com.android.keyguard.KeyguardViewBase}.
435cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi */
445cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggipublic class StatusBarKeyguardViewManager {
455cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    private static String TAG = "StatusBarKeyguardViewManager";
465cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
475cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    private final Context mContext;
485cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
495cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    private LockPatternUtils mLockPatternUtils;
505cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    private ViewMediatorCallback mViewMediatorCallback;
515cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    private PhoneStatusBar mPhoneStatusBar;
525cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
535cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    private ViewGroup mContainer;
545cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    private StatusBarWindowManager mStatusBarWindowManager;
555cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
565cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    private boolean mScreenOn = false;
5703c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi    private KeyguardBouncer mBouncer;
5803c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi    private boolean mShowing;
595cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
605cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    public StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback,
615cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi            LockPatternUtils lockPatternUtils) {
625cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi        mContext = context;
635cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi        mViewMediatorCallback = callback;
645cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi        mLockPatternUtils = lockPatternUtils;
655cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
665cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
675cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    public void registerStatusBar(PhoneStatusBar phoneStatusBar,
685cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi            ViewGroup container, StatusBarWindowManager statusBarWindowManager) {
695cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi        mPhoneStatusBar = phoneStatusBar;
705cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi        mContainer = container;
715cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi        mStatusBarWindowManager = statusBarWindowManager;
7203c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi        mBouncer = new KeyguardBouncer(mContext, mViewMediatorCallback, mLockPatternUtils,
7303c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi                mStatusBarWindowManager, container);
745cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
755cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
765cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    /**
775cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi     * Show the keyguard.  Will handle creating and attaching to the view manager
785cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi     * lazily.
795cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi     */
805cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    public void show(Bundle options) {
8103c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi        mShowing = true;
82cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi        mStatusBarWindowManager.setKeyguardShowing(true);
83a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi        showBouncerOrKeyguard();
84e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi        updateBackButtonState();
855cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
865cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
87a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi    /**
88a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi     * Shows the notification keyguard or the bouncer depending on
89a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi     * {@link KeyguardBouncer#needsFullscreenBouncer()}.
90a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi     */
91a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi    private void showBouncerOrKeyguard() {
92a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi        if (mBouncer.needsFullscreenBouncer()) {
93a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi
94a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi            // The keyguard might be showing (already). So we need to hide it.
95a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi            mPhoneStatusBar.hideKeyguard();
96a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi            mBouncer.show();
97a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi        } else {
98a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi            mPhoneStatusBar.showKeyguard();
99a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi            mBouncer.hide();
100a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi            mBouncer.prepare();
101a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi        }
102a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi    }
103a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi
10403c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi    public void showBouncer() {
10503c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi        mBouncer.show();
106e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi        updateBackButtonState();
1075cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
1085cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
1095cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    /**
1105cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi     * Reset the state of the view.
1115cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi     */
1125cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    public void reset() {
113a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi        showBouncerOrKeyguard();
114e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi        updateBackButtonState();
1155cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
1165cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
1175cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    public void onScreenTurnedOff() {
1185cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi        mScreenOn = false;
11903c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi        mBouncer.onScreenTurnedOff();
1205cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
1215cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
1225cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    public void onScreenTurnedOn(final IKeyguardShowCallback callback) {
1235cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi        mScreenOn = true;
12403c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi        if (callback != null) {
12503c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi            callbackAfterDraw(callback);
1265cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi        }
1275cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
1285cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
1295cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    private void callbackAfterDraw(final IKeyguardShowCallback callback) {
13003c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi        mContainer.post(new Runnable() {
1315cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi            @Override
1325cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi            public void run() {
1335cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi                try {
13403c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi                    callback.onShown(mContainer.getWindowToken());
1355cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi                } catch (RemoteException e) {
1365cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi                    Slog.w(TAG, "Exception calling onShown():", e);
1375cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi                }
1385cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi            }
1395cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi        });
1405cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
1415cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
1425cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    public void verifyUnlock() {
14303c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi        dismiss();
1445cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
1455cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
1465cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    public void setNeedsInput(boolean needsInput) {
147cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi        mStatusBarWindowManager.setKeyguardNeedsInput(needsInput);
1485cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
1495cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
1505cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    public void updateUserActivityTimeout() {
15103c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi        mStatusBarWindowManager.setKeyguardUserActivityTimeout(mBouncer.getUserActivityTimeout());
1525cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
1535cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
1545cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    public void setOccluded(boolean occluded) {
155cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi        mStatusBarWindowManager.setKeyguardOccluded(occluded);
1565cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
1575cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
1585cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    /**
1595cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi     * Hides the keyguard view
1605cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi     */
1615cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    public void hide() {
16203c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi        mShowing = false;
16303c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi        mPhoneStatusBar.hideKeyguard();
164cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi        mStatusBarWindowManager.setKeyguardShowing(false);
16503c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi        mBouncer.hide();
16603c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi        mViewMediatorCallback.keyguardGone();
1675cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
1685cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
1695cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    /**
1705cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi     * Dismisses the keyguard by going to the next screen or making it gone.
1715cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi     */
1725cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    public void dismiss() {
1735cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi        if (mScreenOn) {
1740bed7f258ba1fffc10f986ee043b769f1fd40ad3Jorim Jaggi            showBouncer();
1755cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi        }
1765cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
1775cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi
1785cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    /**
1795cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi     * @return Whether the keyguard is showing
1805cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi     */
1815cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    public boolean isShowing() {
18203c701ec58ff6de3cc3c53b05342a475a63a11cfJorim Jaggi        return mShowing;
1835cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi    }
184e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi
185e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi    /**
186e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi     * Notifies this manager that the back button has been pressed.
187e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi     *
188e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi     * @return whether the back press has been handled
189e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi     */
190e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi    public boolean onBackPressed() {
191e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi        if (mBouncer.isShowing()) {
192e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi            mBouncer.hide();
193e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi            mPhoneStatusBar.showKeyguard();
194e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi            updateBackButtonState();
195e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi            return true;
196e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi        }
197e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi        return false;
198e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi    }
199e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi
200e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi    private void updateBackButtonState() {
201e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi        int vis = mContainer.getSystemUiVisibility();
202a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi        boolean bouncerDismissable = mBouncer.isShowing() && !mBouncer.needsFullscreenBouncer();
203a005f1b6853e8852c328f4fdc02fb8f9c9ae1cd6Jorim Jaggi        if (bouncerDismissable || !mShowing) {
204e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi            mContainer.setSystemUiVisibility(vis & ~View.STATUS_BAR_DISABLE_BACK);
205e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi        } else {
206e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi            mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK);
207e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi        }
208e5c7a894635d72514d6f1e952d0f18ba6035e86dJorim Jaggi    }
2098c8bcc160aba9a5e93c8df2a99a39a856fafffabJorim Jaggi
2108c8bcc160aba9a5e93c8df2a99a39a856fafffabJorim Jaggi    public boolean onMenuPressed() {
2118c8bcc160aba9a5e93c8df2a99a39a856fafffabJorim Jaggi        return mBouncer.onMenuPressed();
2128c8bcc160aba9a5e93c8df2a99a39a856fafffabJorim Jaggi    }
2135cf17879a31b7b78c09ec50b727f921840dcf783Jorim Jaggi}
214