1/*
2 * Copyright (C) 2011 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
17package com.android.nfc;
18
19import android.app.NotificationManager;
20import android.content.Context;
21import android.content.res.Configuration;
22import android.os.Vibrator;
23
24/**
25 * Manages vibration, sound and animation for P2P events.
26 */
27public class P2pEventManager implements P2pEventListener, SendUi.Callback {
28    static final String TAG = "NfcP2pEventManager";
29    static final boolean DBG = true;
30
31    static final long[] VIBRATION_PATTERN = {0, 100, 10000};
32
33    final Context mContext;
34    final NfcService mNfcService;
35    final P2pEventListener.Callback mCallback;
36    final Vibrator mVibrator;
37    final NotificationManager mNotificationManager;
38    final SendUi mSendUi;
39
40    // only used on UI thread
41    boolean mSending;
42    boolean mNdefSent;
43    boolean mNdefReceived;
44    boolean mInDebounce;
45
46    public P2pEventManager(Context context, P2pEventListener.Callback callback) {
47        mNfcService = NfcService.getInstance();
48        mContext = context;
49        mCallback = callback;
50        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
51        mNotificationManager = (NotificationManager) mContext.getSystemService(
52                Context.NOTIFICATION_SERVICE);
53
54        mSending = false;
55        final int uiModeType = mContext.getResources().getConfiguration().uiMode
56                & Configuration.UI_MODE_TYPE_MASK;
57        if (uiModeType == Configuration.UI_MODE_TYPE_APPLIANCE) {
58            // "Appliances" don't intrinsically have a way of confirming this, so we
59            // don't use the UI and just autoconfirm where necessary.
60            // Don't instantiate SendUi or else we'll use memory and never reclaim it.
61            mSendUi = null;
62        } else {
63            mSendUi = new SendUi(context, this);
64        }
65    }
66
67    @Override
68    public void onP2pInRange() {
69        mNfcService.playSound(NfcService.SOUND_START);
70        mNdefSent = false;
71        mNdefReceived = false;
72        mInDebounce = false;
73
74        mVibrator.vibrate(VIBRATION_PATTERN, -1);
75        if (mSendUi != null) {
76            mSendUi.takeScreenshot();
77        }
78    }
79
80    @Override
81    public void onP2pSendConfirmationRequested() {
82        if (mSendUi != null) {
83            mSendUi.showPreSend();
84        } else {
85            mCallback.onP2pSendConfirmed();
86        }
87    }
88
89    @Override
90    public void onP2pSendComplete() {
91        mNfcService.playSound(NfcService.SOUND_END);
92        mVibrator.vibrate(VIBRATION_PATTERN, -1);
93        if (mSendUi != null) {
94            mSendUi.finish(SendUi.FINISH_SEND_SUCCESS);
95        }
96        mSending = false;
97        mNdefSent = true;
98    }
99
100    @Override
101    public void onP2pHandoverNotSupported() {
102        mNfcService.playSound(NfcService.SOUND_ERROR);
103        mVibrator.vibrate(VIBRATION_PATTERN, -1);
104        mSendUi.finishAndToast(SendUi.FINISH_SCALE_UP,
105                mContext.getString(R.string.beam_handover_not_supported));
106        mSending = false;
107        mNdefSent = false;
108    }
109
110    @Override
111    public void onP2pReceiveComplete(boolean playSound) {
112        mVibrator.vibrate(VIBRATION_PATTERN, -1);
113        if (playSound) mNfcService.playSound(NfcService.SOUND_END);
114        if (mSendUi != null) {
115            // TODO we still don't have a nice receive solution
116            // The sanest solution right now is just to scale back up what we had
117            // and start the new activity. It is not perfect, but at least it is
118            // consistent behavior. All other variants involve making the old
119            // activity screenshot disappear, and then removing the animation
120            // window hoping the new activity has started by then. This just goes
121            // wrong too often and can look weird.
122            mSendUi.finish(SendUi.FINISH_SCALE_UP);
123        }
124        mNdefReceived = true;
125    }
126
127    @Override
128    public void onP2pOutOfRange() {
129        if (mSending) {
130            mNfcService.playSound(NfcService.SOUND_ERROR);
131            mSending = false;
132        }
133        if (!mNdefSent && !mNdefReceived && mSendUi != null) {
134            mSendUi.finish(SendUi.FINISH_SCALE_UP);
135        }
136        mInDebounce = false;
137    }
138
139    @Override
140    public void onSendConfirmed() {
141        if (!mSending) {
142            if (mSendUi != null) {
143                mSendUi.showStartSend();
144            }
145            mCallback.onP2pSendConfirmed();
146        }
147        mSending = true;
148
149    }
150
151    @Override
152    public void onP2pSendDebounce() {
153        mInDebounce = true;
154        mNfcService.playSound(NfcService.SOUND_ERROR);
155        if (mSendUi != null) {
156            mSendUi.showSendHint();
157        }
158    }
159
160    @Override
161    public void onP2pResumeSend() {
162        if (mInDebounce) {
163            mVibrator.vibrate(VIBRATION_PATTERN, -1);
164            mNfcService.playSound(NfcService.SOUND_START);
165            if (mSendUi != null) {
166                mSendUi.showStartSend();
167            }
168        }
169        mInDebounce = false;
170    }
171}
172