NfcActivityManager.java revision 56f299b87a891db38691cc0260f761c3ce8ef9ac
1aeb094b520d8ea49b74129927578f18f758c873eJason Sams/*
2aeb094b520d8ea49b74129927578f18f758c873eJason Sams * Copyright (C) 2011 The Android Open Source Project
3aeb094b520d8ea49b74129927578f18f758c873eJason Sams *
4aeb094b520d8ea49b74129927578f18f758c873eJason Sams * Licensed under the Apache License, Version 2.0 (the "License");
5aeb094b520d8ea49b74129927578f18f758c873eJason Sams * you may not use this file except in compliance with the License.
6aeb094b520d8ea49b74129927578f18f758c873eJason Sams * You may obtain a copy of the License at
7aeb094b520d8ea49b74129927578f18f758c873eJason Sams *
8aeb094b520d8ea49b74129927578f18f758c873eJason Sams *      http://www.apache.org/licenses/LICENSE-2.0
9aeb094b520d8ea49b74129927578f18f758c873eJason Sams *
10aeb094b520d8ea49b74129927578f18f758c873eJason Sams * Unless required by applicable law or agreed to in writing, software
11aeb094b520d8ea49b74129927578f18f758c873eJason Sams * distributed under the License is distributed on an "AS IS" BASIS,
12aeb094b520d8ea49b74129927578f18f758c873eJason Sams * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aeb094b520d8ea49b74129927578f18f758c873eJason Sams * See the License for the specific language governing permissions and
14aeb094b520d8ea49b74129927578f18f758c873eJason Sams * limitations under the License.
15aeb094b520d8ea49b74129927578f18f758c873eJason Sams */
16aeb094b520d8ea49b74129927578f18f758c873eJason Sams
17aeb094b520d8ea49b74129927578f18f758c873eJason Samspackage android.nfc;
18aeb094b520d8ea49b74129927578f18f758c873eJason Sams
19aeb094b520d8ea49b74129927578f18f758c873eJason Samsimport android.app.Activity;
20aeb094b520d8ea49b74129927578f18f758c873eJason Samsimport android.app.Application;
21aeb094b520d8ea49b74129927578f18f758c873eJason Samsimport android.content.ContentProvider;
22aeb094b520d8ea49b74129927578f18f758c873eJason Samsimport android.content.Intent;
23aeb094b520d8ea49b74129927578f18f758c873eJason Samsimport android.net.Uri;
24aeb094b520d8ea49b74129927578f18f758c873eJason Samsimport android.nfc.NfcAdapter.ReaderCallback;
25aeb094b520d8ea49b74129927578f18f758c873eJason Samsimport android.os.Binder;
26aeb094b520d8ea49b74129927578f18f758c873eJason Samsimport android.os.Bundle;
27aeb094b520d8ea49b74129927578f18f758c873eJason Samsimport android.os.RemoteException;
28aeb094b520d8ea49b74129927578f18f758c873eJason Samsimport android.os.UserHandle;
29aeb094b520d8ea49b74129927578f18f758c873eJason Samsimport android.util.Log;
30aeb094b520d8ea49b74129927578f18f758c873eJason Sams
31aeb094b520d8ea49b74129927578f18f758c873eJason Samsimport java.util.ArrayList;
32aeb094b520d8ea49b74129927578f18f758c873eJason Samsimport java.util.LinkedList;
33aeb094b520d8ea49b74129927578f18f758c873eJason Samsimport java.util.List;
34aeb094b520d8ea49b74129927578f18f758c873eJason Sams
35aeb094b520d8ea49b74129927578f18f758c873eJason Sams/**
36aeb094b520d8ea49b74129927578f18f758c873eJason Sams * Manages NFC API's that are coupled to the life-cycle of an Activity.
37aeb094b520d8ea49b74129927578f18f758c873eJason Sams *
38aeb094b520d8ea49b74129927578f18f758c873eJason Sams * <p>Uses {@link Application#registerActivityLifecycleCallbacks} to hook
39aeb094b520d8ea49b74129927578f18f758c873eJason Sams * into activity life-cycle events such as onPause() and onResume().
40aeb094b520d8ea49b74129927578f18f758c873eJason Sams *
41aeb094b520d8ea49b74129927578f18f758c873eJason Sams * @hide
42aeb094b520d8ea49b74129927578f18f758c873eJason Sams */
43aeb094b520d8ea49b74129927578f18f758c873eJason Samspublic final class NfcActivityManager extends IAppCallback.Stub
44aeb094b520d8ea49b74129927578f18f758c873eJason Sams        implements Application.ActivityLifecycleCallbacks {
45aeb094b520d8ea49b74129927578f18f758c873eJason Sams    static final String TAG = NfcAdapter.TAG;
46aeb094b520d8ea49b74129927578f18f758c873eJason Sams    static final Boolean DBG = false;
47605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams
48605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams    final NfcAdapter mAdapter;
49aeb094b520d8ea49b74129927578f18f758c873eJason Sams    final NfcEvent mDefaultEvent;  // cached NfcEvent (its currently always the same)
50aeb094b520d8ea49b74129927578f18f758c873eJason Sams
51aeb094b520d8ea49b74129927578f18f758c873eJason Sams    // All objects in the lists are protected by this
52aeb094b520d8ea49b74129927578f18f758c873eJason Sams    final List<NfcApplicationState> mApps;  // Application(s) that have NFC state. Usually one
53aeb094b520d8ea49b74129927578f18f758c873eJason Sams    final List<NfcActivityState> mActivities;  // Activities that have NFC state
54aeb094b520d8ea49b74129927578f18f758c873eJason Sams
55aeb094b520d8ea49b74129927578f18f758c873eJason Sams    /**
56aeb094b520d8ea49b74129927578f18f758c873eJason Sams     * NFC State associated with an {@link Application}.
57aeb094b520d8ea49b74129927578f18f758c873eJason Sams     */
58aeb094b520d8ea49b74129927578f18f758c873eJason Sams    class NfcApplicationState {
59605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams        int refCount = 0;
60605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams        final Application app;
61aeb094b520d8ea49b74129927578f18f758c873eJason Sams        public NfcApplicationState(Application app) {
62aeb094b520d8ea49b74129927578f18f758c873eJason Sams            this.app = app;
63aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
64aeb094b520d8ea49b74129927578f18f758c873eJason Sams        public void register() {
65aeb094b520d8ea49b74129927578f18f758c873eJason Sams            refCount++;
66aeb094b520d8ea49b74129927578f18f758c873eJason Sams            if (refCount == 1) {
67aeb094b520d8ea49b74129927578f18f758c873eJason Sams                this.app.registerActivityLifecycleCallbacks(NfcActivityManager.this);
68aeb094b520d8ea49b74129927578f18f758c873eJason Sams            }
69aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
70aeb094b520d8ea49b74129927578f18f758c873eJason Sams        public void unregister() {
71605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams            refCount--;
72aeb094b520d8ea49b74129927578f18f758c873eJason Sams            if (refCount == 0) {
73aeb094b520d8ea49b74129927578f18f758c873eJason Sams                this.app.unregisterActivityLifecycleCallbacks(NfcActivityManager.this);
74aeb094b520d8ea49b74129927578f18f758c873eJason Sams            } else if (refCount < 0) {
75aeb094b520d8ea49b74129927578f18f758c873eJason Sams                Log.e(TAG, "-ve refcount for " + app);
76aeb094b520d8ea49b74129927578f18f758c873eJason Sams            }
77aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
78605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams    }
79aeb094b520d8ea49b74129927578f18f758c873eJason Sams
80aeb094b520d8ea49b74129927578f18f758c873eJason Sams    NfcApplicationState findAppState(Application app) {
81aeb094b520d8ea49b74129927578f18f758c873eJason Sams        for (NfcApplicationState appState : mApps) {
82aeb094b520d8ea49b74129927578f18f758c873eJason Sams            if (appState.app == app) {
83aeb094b520d8ea49b74129927578f18f758c873eJason Sams                return appState;
84aeb094b520d8ea49b74129927578f18f758c873eJason Sams            }
85605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams        }
86aeb094b520d8ea49b74129927578f18f758c873eJason Sams        return null;
87aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
88aeb094b520d8ea49b74129927578f18f758c873eJason Sams
89aeb094b520d8ea49b74129927578f18f758c873eJason Sams    void registerApplication(Application app) {
90aeb094b520d8ea49b74129927578f18f758c873eJason Sams        NfcApplicationState appState = findAppState(app);
91aeb094b520d8ea49b74129927578f18f758c873eJason Sams        if (appState == null) {
92605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams            appState = new NfcApplicationState(app);
93aeb094b520d8ea49b74129927578f18f758c873eJason Sams            mApps.add(appState);
94aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
95aeb094b520d8ea49b74129927578f18f758c873eJason Sams        appState.register();
96aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
97aeb094b520d8ea49b74129927578f18f758c873eJason Sams
98aeb094b520d8ea49b74129927578f18f758c873eJason Sams    void unregisterApplication(Application app) {
99aeb094b520d8ea49b74129927578f18f758c873eJason Sams        NfcApplicationState appState = findAppState(app);
100aeb094b520d8ea49b74129927578f18f758c873eJason Sams        if (appState == null) {
101a490f1003a76286e0f00606adff4ef85fdd78b02Jim Miller            Log.e(TAG, "app was not registered " + app);
102a490f1003a76286e0f00606adff4ef85fdd78b02Jim Miller            return;
103a490f1003a76286e0f00606adff4ef85fdd78b02Jim Miller        }
104383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk        appState.unregister();
105a490f1003a76286e0f00606adff4ef85fdd78b02Jim Miller    }
106a490f1003a76286e0f00606adff4ef85fdd78b02Jim Miller
107aeb094b520d8ea49b74129927578f18f758c873eJason Sams    /**
108aeb094b520d8ea49b74129927578f18f758c873eJason Sams     * NFC state associated with an {@link Activity}
109aeb094b520d8ea49b74129927578f18f758c873eJason Sams     */
110383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    class NfcActivityState {
111aeb094b520d8ea49b74129927578f18f758c873eJason Sams        boolean resumed = false;
112aeb094b520d8ea49b74129927578f18f758c873eJason Sams        Activity activity;
113aeb094b520d8ea49b74129927578f18f758c873eJason Sams        NdefMessage ndefMessage = null;  // static NDEF message
114aeb094b520d8ea49b74129927578f18f758c873eJason Sams        NfcAdapter.CreateNdefMessageCallback ndefMessageCallback = null;
115aeb094b520d8ea49b74129927578f18f758c873eJason Sams        NfcAdapter.OnNdefPushCompleteCallback onNdefPushCompleteCallback = null;
116383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk        NfcAdapter.CreateBeamUrisCallback uriCallback = null;
117aeb094b520d8ea49b74129927578f18f758c873eJason Sams        Uri[] uris = null;
118aeb094b520d8ea49b74129927578f18f758c873eJason Sams        int flags = 0;
119aeb094b520d8ea49b74129927578f18f758c873eJason Sams        int readerModeFlags = 0;
1206445e5210c6d7f8689e94be9026153d017c9545bJason Sams        NfcAdapter.ReaderCallback readerCallback = null;
1216445e5210c6d7f8689e94be9026153d017c9545bJason Sams        Bundle readerModeExtras = null;
122383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk        Binder token;
123605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams
1246445e5210c6d7f8689e94be9026153d017c9545bJason Sams        public NfcActivityState(Activity activity) {
125383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk            if (activity.getWindow().isDestroyed()) {
1266445e5210c6d7f8689e94be9026153d017c9545bJason Sams                throw new IllegalStateException("activity is already destroyed");
1276445e5210c6d7f8689e94be9026153d017c9545bJason Sams            }
12895333f998fd4a983f89e5128e85f6f710d200bd9Alex Sakhartchouk            // Check if activity is resumed right now, as we will not
12995333f998fd4a983f89e5128e85f6f710d200bd9Alex Sakhartchouk            // immediately get a callback for that.
13095333f998fd4a983f89e5128e85f6f710d200bd9Alex Sakhartchouk            resumed = activity.isResumed();
131383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk
13295333f998fd4a983f89e5128e85f6f710d200bd9Alex Sakhartchouk            this.activity = activity;
13395333f998fd4a983f89e5128e85f6f710d200bd9Alex Sakhartchouk            this.token = new Binder();
134aeb094b520d8ea49b74129927578f18f758c873eJason Sams            registerApplication(activity.getApplication());
135aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
136aeb094b520d8ea49b74129927578f18f758c873eJason Sams        public void destroy() {
137aeb094b520d8ea49b74129927578f18f758c873eJason Sams            unregisterApplication(activity.getApplication());
138aeb094b520d8ea49b74129927578f18f758c873eJason Sams            resumed = false;
139aeb094b520d8ea49b74129927578f18f758c873eJason Sams            activity = null;
140aeb094b520d8ea49b74129927578f18f758c873eJason Sams            ndefMessage = null;
141aeb094b520d8ea49b74129927578f18f758c873eJason Sams            ndefMessageCallback = null;
142aeb094b520d8ea49b74129927578f18f758c873eJason Sams            onNdefPushCompleteCallback = null;
143aeb094b520d8ea49b74129927578f18f758c873eJason Sams            uriCallback = null;
144aeb094b520d8ea49b74129927578f18f758c873eJason Sams            uris = null;
145aeb094b520d8ea49b74129927578f18f758c873eJason Sams            readerModeFlags = 0;
146aeb094b520d8ea49b74129927578f18f758c873eJason Sams            token = null;
147aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
148aeb094b520d8ea49b74129927578f18f758c873eJason Sams        @Override
149aeb094b520d8ea49b74129927578f18f758c873eJason Sams        public String toString() {
150aeb094b520d8ea49b74129927578f18f758c873eJason Sams            StringBuilder s = new StringBuilder("[").append(" ");
151aeb094b520d8ea49b74129927578f18f758c873eJason Sams            s.append(ndefMessage).append(" ").append(ndefMessageCallback).append(" ");
152aeb094b520d8ea49b74129927578f18f758c873eJason Sams            s.append(uriCallback).append(" ");
153aeb094b520d8ea49b74129927578f18f758c873eJason Sams            if (uris != null) {
154aeb094b520d8ea49b74129927578f18f758c873eJason Sams                for (Uri uri : uris) {
155aeb094b520d8ea49b74129927578f18f758c873eJason Sams                    s.append(onNdefPushCompleteCallback).append(" ").append(uri).append("]");
156aeb094b520d8ea49b74129927578f18f758c873eJason Sams                }
157aeb094b520d8ea49b74129927578f18f758c873eJason Sams            }
158aeb094b520d8ea49b74129927578f18f758c873eJason Sams            return s.toString();
159aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
160aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
161aeb094b520d8ea49b74129927578f18f758c873eJason Sams
162aeb094b520d8ea49b74129927578f18f758c873eJason Sams    /** find activity state from mActivities */
163886f11ade9dde05485cb11c0d67d87f76a428f6cAlex Sakhartchouk    synchronized NfcActivityState findActivityState(Activity activity) {
164886f11ade9dde05485cb11c0d67d87f76a428f6cAlex Sakhartchouk        for (NfcActivityState state : mActivities) {
16579f52df541f87ac07709e770cd79f14dd1a05e93Jason Sams            if (state.activity == activity) {
166aeb094b520d8ea49b74129927578f18f758c873eJason Sams                return state;
167aeb094b520d8ea49b74129927578f18f758c873eJason Sams            }
168aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
169aeb094b520d8ea49b74129927578f18f758c873eJason Sams        return null;
170aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
171aeb094b520d8ea49b74129927578f18f758c873eJason Sams
172aeb094b520d8ea49b74129927578f18f758c873eJason Sams    /** find or create activity state from mActivities */
173aeb094b520d8ea49b74129927578f18f758c873eJason Sams    synchronized NfcActivityState getActivityState(Activity activity) {
174aeb094b520d8ea49b74129927578f18f758c873eJason Sams        NfcActivityState state = findActivityState(activity);
175aeb094b520d8ea49b74129927578f18f758c873eJason Sams        if (state == null) {
176aeb094b520d8ea49b74129927578f18f758c873eJason Sams            state = new NfcActivityState(activity);
177aeb094b520d8ea49b74129927578f18f758c873eJason Sams            mActivities.add(state);
178aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
179aeb094b520d8ea49b74129927578f18f758c873eJason Sams        return state;
180aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
181aeb094b520d8ea49b74129927578f18f758c873eJason Sams
182aeb094b520d8ea49b74129927578f18f758c873eJason Sams    synchronized NfcActivityState findResumedActivityState() {
183aeb094b520d8ea49b74129927578f18f758c873eJason Sams        for (NfcActivityState state : mActivities) {
184aeb094b520d8ea49b74129927578f18f758c873eJason Sams            if (state.resumed) {
185aeb094b520d8ea49b74129927578f18f758c873eJason Sams                return state;
186aeb094b520d8ea49b74129927578f18f758c873eJason Sams            }
187aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
188aeb094b520d8ea49b74129927578f18f758c873eJason Sams        return null;
189aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
190aeb094b520d8ea49b74129927578f18f758c873eJason Sams
191aeb094b520d8ea49b74129927578f18f758c873eJason Sams    synchronized void destroyActivityState(Activity activity) {
192aeb094b520d8ea49b74129927578f18f758c873eJason Sams        NfcActivityState activityState = findActivityState(activity);
193aeb094b520d8ea49b74129927578f18f758c873eJason Sams        if (activityState != null) {
194aeb094b520d8ea49b74129927578f18f758c873eJason Sams            activityState.destroy();
195aeb094b520d8ea49b74129927578f18f758c873eJason Sams            mActivities.remove(activityState);
196aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
197aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
198bdb046001675f949e7e9b2cd0bfd63a5889d97edJason Sams
199aeb094b520d8ea49b74129927578f18f758c873eJason Sams    public NfcActivityManager(NfcAdapter adapter) {
200aeb094b520d8ea49b74129927578f18f758c873eJason Sams        mAdapter = adapter;
201aeb094b520d8ea49b74129927578f18f758c873eJason Sams        mActivities = new LinkedList<NfcActivityState>();
202aeb094b520d8ea49b74129927578f18f758c873eJason Sams        mApps = new ArrayList<NfcApplicationState>(1);  // Android VM usually has 1 app
203aeb094b520d8ea49b74129927578f18f758c873eJason Sams        mDefaultEvent = new NfcEvent(mAdapter);
204aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
205aeb094b520d8ea49b74129927578f18f758c873eJason Sams
206aeb094b520d8ea49b74129927578f18f758c873eJason Sams    public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
207aeb094b520d8ea49b74129927578f18f758c873eJason Sams            Bundle extras) {
208aeb094b520d8ea49b74129927578f18f758c873eJason Sams        boolean isResumed;
209aeb094b520d8ea49b74129927578f18f758c873eJason Sams        Binder token;
210aeb094b520d8ea49b74129927578f18f758c873eJason Sams        synchronized (NfcActivityManager.this) {
211aeb094b520d8ea49b74129927578f18f758c873eJason Sams            NfcActivityState state = getActivityState(activity);
212aeb094b520d8ea49b74129927578f18f758c873eJason Sams            state.readerCallback = callback;
213aeb094b520d8ea49b74129927578f18f758c873eJason Sams            state.readerModeFlags = flags;
214aeb094b520d8ea49b74129927578f18f758c873eJason Sams            state.readerModeExtras = extras;
215aeb094b520d8ea49b74129927578f18f758c873eJason Sams            token = state.token;
216aeb094b520d8ea49b74129927578f18f758c873eJason Sams            isResumed = state.resumed;
217aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
218aeb094b520d8ea49b74129927578f18f758c873eJason Sams        if (isResumed) {
219aeb094b520d8ea49b74129927578f18f758c873eJason Sams            setReaderMode(token, flags, extras);
220aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
221aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
222aeb094b520d8ea49b74129927578f18f758c873eJason Sams
223aeb094b520d8ea49b74129927578f18f758c873eJason Sams    public void disableReaderMode(Activity activity) {
224aeb094b520d8ea49b74129927578f18f758c873eJason Sams        boolean isResumed;
225aeb094b520d8ea49b74129927578f18f758c873eJason Sams        Binder token;
226bdb046001675f949e7e9b2cd0bfd63a5889d97edJason Sams        synchronized (NfcActivityManager.this) {
227aeb094b520d8ea49b74129927578f18f758c873eJason Sams            NfcActivityState state = getActivityState(activity);
228aeb094b520d8ea49b74129927578f18f758c873eJason Sams            state.readerCallback = null;
229aeb094b520d8ea49b74129927578f18f758c873eJason Sams            state.readerModeFlags = 0;
230aeb094b520d8ea49b74129927578f18f758c873eJason Sams            state.readerModeExtras = null;
231aeb094b520d8ea49b74129927578f18f758c873eJason Sams            token = state.token;
232aeb094b520d8ea49b74129927578f18f758c873eJason Sams            isResumed = state.resumed;
233aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
234aeb094b520d8ea49b74129927578f18f758c873eJason Sams        if (isResumed) {
235aeb094b520d8ea49b74129927578f18f758c873eJason Sams            setReaderMode(token, 0, null);
236aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
237aeb094b520d8ea49b74129927578f18f758c873eJason Sams
2384e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk    }
2394e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk
240605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams    public void setReaderMode(Binder token, int flags, Bundle extras) {
2414e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk        if (DBG) Log.d(TAG, "Setting reader mode");
2424e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk        try {
243aeb094b520d8ea49b74129927578f18f758c873eJason Sams            NfcAdapter.sService.setReaderMode(token, this, flags, extras);
244aeb094b520d8ea49b74129927578f18f758c873eJason Sams        } catch (RemoteException e) {
245aeb094b520d8ea49b74129927578f18f758c873eJason Sams            mAdapter.attemptDeadServiceRecovery(e);
246aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
247aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
248aeb094b520d8ea49b74129927578f18f758c873eJason Sams
2494e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk    public void setNdefPushContentUri(Activity activity, Uri[] uris) {
250aeb094b520d8ea49b74129927578f18f758c873eJason Sams        boolean isResumed;
251605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams        synchronized (NfcActivityManager.this) {
252aeb094b520d8ea49b74129927578f18f758c873eJason Sams            NfcActivityState state = getActivityState(activity);
2534e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk            state.uris = uris;
254aeb094b520d8ea49b74129927578f18f758c873eJason Sams            isResumed = state.resumed;
255aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
256aeb094b520d8ea49b74129927578f18f758c873eJason Sams        if (isResumed) {
2574e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk            requestNfcServiceCallback();
2584e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk        }
2594e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk    }
2604e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk
2614e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk
262605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams    public void setNdefPushContentUriCallback(Activity activity,
2634e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk            NfcAdapter.CreateBeamUrisCallback callback) {
2644e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk        boolean isResumed;
2654e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk        synchronized (NfcActivityManager.this) {
2664e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk            NfcActivityState state = getActivityState(activity);
2674e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk            state.uriCallback = callback;
2684e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk            isResumed = state.resumed;
269aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
270aeb094b520d8ea49b74129927578f18f758c873eJason Sams        if (isResumed) {
271ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk            requestNfcServiceCallback();
272ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk        }
273ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk    }
274605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams
275ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk    public void setNdefPushMessage(Activity activity, NdefMessage message, int flags) {
276ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk        boolean isResumed;
277ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk        synchronized (NfcActivityManager.this) {
278ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk            NfcActivityState state = getActivityState(activity);
279ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk            state.ndefMessage = message;
280ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk            state.flags = flags;
281ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk            isResumed = state.resumed;
282ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk        }
283ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk        if (isResumed) {
284ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk            requestNfcServiceCallback();
285ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk        }
286aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
287aeb094b520d8ea49b74129927578f18f758c873eJason Sams
288aeb094b520d8ea49b74129927578f18f758c873eJason Sams    public void setNdefPushMessageCallback(Activity activity,
289aeb094b520d8ea49b74129927578f18f758c873eJason Sams            NfcAdapter.CreateNdefMessageCallback callback, int flags) {
290aeb094b520d8ea49b74129927578f18f758c873eJason Sams        boolean isResumed;
291aeb094b520d8ea49b74129927578f18f758c873eJason Sams        synchronized (NfcActivityManager.this) {
292aeb094b520d8ea49b74129927578f18f758c873eJason Sams            NfcActivityState state = getActivityState(activity);
293aeb094b520d8ea49b74129927578f18f758c873eJason Sams            state.ndefMessageCallback = callback;
294aeb094b520d8ea49b74129927578f18f758c873eJason Sams            state.flags = flags;
2956445e5210c6d7f8689e94be9026153d017c9545bJason Sams            isResumed = state.resumed;
296383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk        }
297aeb094b520d8ea49b74129927578f18f758c873eJason Sams        if (isResumed) {
298aeb094b520d8ea49b74129927578f18f758c873eJason Sams            requestNfcServiceCallback();
29922fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams        }
300aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
301605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams
302aeb094b520d8ea49b74129927578f18f758c873eJason Sams    public void setOnNdefPushCompleteCallback(Activity activity,
303aeb094b520d8ea49b74129927578f18f758c873eJason Sams            NfcAdapter.OnNdefPushCompleteCallback callback) {
304aeb094b520d8ea49b74129927578f18f758c873eJason Sams        boolean isResumed;
30522fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams        synchronized (NfcActivityManager.this) {
30622fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams            NfcActivityState state = getActivityState(activity);
307605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams            state.onNdefPushCompleteCallback = callback;
30822fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams            isResumed = state.resumed;
30922fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams        }
31022fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams        if (isResumed) {
311aeb094b520d8ea49b74129927578f18f758c873eJason Sams            requestNfcServiceCallback();
312aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
313aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
314605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams
315aeb094b520d8ea49b74129927578f18f758c873eJason Sams    /**
316aeb094b520d8ea49b74129927578f18f758c873eJason Sams     * Request or unrequest NFC service callbacks.
317aeb094b520d8ea49b74129927578f18f758c873eJason Sams     * Makes IPC call - do not hold lock.
318aeb094b520d8ea49b74129927578f18f758c873eJason Sams     */
31922fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams    void requestNfcServiceCallback() {
320aeb094b520d8ea49b74129927578f18f758c873eJason Sams        try {
321aeb094b520d8ea49b74129927578f18f758c873eJason Sams            NfcAdapter.sService.setAppCallback(this);
32222fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams        } catch (RemoteException e) {
32322fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams            mAdapter.attemptDeadServiceRecovery(e);
32422fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams        }
325aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
32622fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams
32722fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams    /** Callback from NFC service, usually on binder thread */
328aeb094b520d8ea49b74129927578f18f758c873eJason Sams    @Override
329aeb094b520d8ea49b74129927578f18f758c873eJason Sams    public BeamShareData createBeamShareData() {
33022fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams        NfcAdapter.CreateNdefMessageCallback ndefCallback;
331aeb094b520d8ea49b74129927578f18f758c873eJason Sams        NfcAdapter.CreateBeamUrisCallback urisCallback;
332aeb094b520d8ea49b74129927578f18f758c873eJason Sams        NdefMessage message;
33322fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams        Activity activity;
33422fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams        Uri[] uris;
33522fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams        int flags;
33622fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams        synchronized (NfcActivityManager.this) {
33722fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams            NfcActivityState state = findResumedActivityState();
33822fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams            if (state == null) return null;
339aeb094b520d8ea49b74129927578f18f758c873eJason Sams
340aeb094b520d8ea49b74129927578f18f758c873eJason Sams            ndefCallback = state.ndefMessageCallback;
341aeb094b520d8ea49b74129927578f18f758c873eJason Sams            urisCallback = state.uriCallback;
342aeb094b520d8ea49b74129927578f18f758c873eJason Sams            message = state.ndefMessage;
343aeb094b520d8ea49b74129927578f18f758c873eJason Sams            uris = state.uris;
344aeb094b520d8ea49b74129927578f18f758c873eJason Sams            flags = state.flags;
345aeb094b520d8ea49b74129927578f18f758c873eJason Sams            activity = state.activity;
346aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
347aeb094b520d8ea49b74129927578f18f758c873eJason Sams
348aeb094b520d8ea49b74129927578f18f758c873eJason Sams        // Make callbacks without lock
349aeb094b520d8ea49b74129927578f18f758c873eJason Sams        if (ndefCallback != null) {
350aeb094b520d8ea49b74129927578f18f758c873eJason Sams            message  = ndefCallback.createNdefMessage(mDefaultEvent);
351aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
352aeb094b520d8ea49b74129927578f18f758c873eJason Sams        if (urisCallback != null) {
353d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            uris = urisCallback.createBeamUris(mDefaultEvent);
354d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            if (uris != null) {
355605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams                ArrayList<Uri> validUris = new ArrayList<Uri>();
356d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                for (Uri uri : uris) {
357d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                    if (uri == null) {
358d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                        Log.e(TAG, "Uri not allowed to be null.");
359d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                        continue;
360d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                    }
361d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                    String scheme = uri.getScheme();
362d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                    if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
363d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            !scheme.equalsIgnoreCase("content"))) {
364d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                        Log.e(TAG, "Uri needs to have " +
365d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                "either scheme file or scheme content");
366d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                        continue;
367d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                    }
368d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                    uri = ContentProvider.maybeAddUserId(uri, UserHandle.myUserId());
369605048a9f9af925782f6c90bc1cdc5af59e337d8Jason Sams                    validUris.add(uri);
370d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                }
371d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
372d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                uris = validUris.toArray(new Uri[validUris.size()]);
373aeb094b520d8ea49b74129927578f18f758c873eJason Sams            }
3749fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk        }
3759fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk        if (uris != null && uris.length > 0) {
3769fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk            for (Uri uri : uris) {
3779fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk                // Grant the NFC process permission to read these URIs
3789fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk                activity.grantUriPermission("com.android.nfc", uri,
3799fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk                        Intent.FLAG_GRANT_READ_URI_PERMISSION);
380aeb094b520d8ea49b74129927578f18f758c873eJason Sams            }
381aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
382aeb094b520d8ea49b74129927578f18f758c873eJason Sams        return new BeamShareData(message, uris, UserHandle.CURRENT, flags);
383aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
384aeb094b520d8ea49b74129927578f18f758c873eJason Sams
385aeb094b520d8ea49b74129927578f18f758c873eJason Sams    /** Callback from NFC service, usually on binder thread */
386aeb094b520d8ea49b74129927578f18f758c873eJason Sams    @Override
387aeb094b520d8ea49b74129927578f18f758c873eJason Sams    public void onNdefPushComplete() {
388aeb094b520d8ea49b74129927578f18f758c873eJason Sams        NfcAdapter.OnNdefPushCompleteCallback callback;
389aeb094b520d8ea49b74129927578f18f758c873eJason Sams        synchronized (NfcActivityManager.this) {
390aeb094b520d8ea49b74129927578f18f758c873eJason Sams            NfcActivityState state = findResumedActivityState();
391aeb094b520d8ea49b74129927578f18f758c873eJason Sams            if (state == null) return;
392aeb094b520d8ea49b74129927578f18f758c873eJason Sams
393aeb094b520d8ea49b74129927578f18f758c873eJason Sams            callback = state.onNdefPushCompleteCallback;
394aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
395aeb094b520d8ea49b74129927578f18f758c873eJason Sams
396aeb094b520d8ea49b74129927578f18f758c873eJason Sams        // Make callback without lock
397aeb094b520d8ea49b74129927578f18f758c873eJason Sams        if (callback != null) {
398aeb094b520d8ea49b74129927578f18f758c873eJason Sams            callback.onNdefPushComplete(mDefaultEvent);
399aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
400aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
401aeb094b520d8ea49b74129927578f18f758c873eJason Sams
4027349547db61d2d458b31c074b902d56d082e5d84Jason Sams    @Override
4037349547db61d2d458b31c074b902d56d082e5d84Jason Sams    public void onTagDiscovered(Tag tag) throws RemoteException {
4047349547db61d2d458b31c074b902d56d082e5d84Jason Sams        NfcAdapter.ReaderCallback callback;
4057349547db61d2d458b31c074b902d56d082e5d84Jason Sams        synchronized (NfcActivityManager.this) {
4067349547db61d2d458b31c074b902d56d082e5d84Jason Sams            NfcActivityState state = findResumedActivityState();
4077349547db61d2d458b31c074b902d56d082e5d84Jason Sams            if (state == null) return;
40822fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams
4097349547db61d2d458b31c074b902d56d082e5d84Jason Sams            callback = state.readerCallback;
4107349547db61d2d458b31c074b902d56d082e5d84Jason Sams        }
4117349547db61d2d458b31c074b902d56d082e5d84Jason Sams
41222fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams        // Make callback without lock
41395333f998fd4a983f89e5128e85f6f710d200bd9Alex Sakhartchouk        if (callback != null) {
41495333f998fd4a983f89e5128e85f6f710d200bd9Alex Sakhartchouk            callback.onTagDiscovered(tag);
4156445e5210c6d7f8689e94be9026153d017c9545bJason Sams        }
4166445e5210c6d7f8689e94be9026153d017c9545bJason Sams
4177349547db61d2d458b31c074b902d56d082e5d84Jason Sams    }
4187349547db61d2d458b31c074b902d56d082e5d84Jason Sams    /** Callback from Activity life-cycle, on main thread */
41922fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams    @Override
4207349547db61d2d458b31c074b902d56d082e5d84Jason Sams    public void onActivityCreated(Activity activity, Bundle savedInstanceState) { /* NO-OP */ }
4218c88090e8cccab103eebe2ff569e116e9f5fb208Jason Sams
4227349547db61d2d458b31c074b902d56d082e5d84Jason Sams    /** Callback from Activity life-cycle, on main thread */
42322fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams    @Override
4247349547db61d2d458b31c074b902d56d082e5d84Jason Sams    public void onActivityStarted(Activity activity) { /* NO-OP */ }
4257349547db61d2d458b31c074b902d56d082e5d84Jason Sams
4267349547db61d2d458b31c074b902d56d082e5d84Jason Sams    /** Callback from Activity life-cycle, on main thread */
4277349547db61d2d458b31c074b902d56d082e5d84Jason Sams    @Override
42822fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams    public void onActivityResumed(Activity activity) {
4294e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk        int readerModeFlags = 0;
4307349547db61d2d458b31c074b902d56d082e5d84Jason Sams        Bundle readerModeExtras = null;
4317349547db61d2d458b31c074b902d56d082e5d84Jason Sams        Binder token;
432ba4aa5c768a498bc3fbb8cb5547b7a9ad6f4b771Alex Sakhartchouk        synchronized (NfcActivityManager.this) {
4334e9a7a8ded109e16b163789274899447cef02642Alex Sakhartchouk            NfcActivityState state = findActivityState(activity);
4347349547db61d2d458b31c074b902d56d082e5d84Jason Sams            if (DBG) Log.d(TAG, "onResume() for " + activity + " " + state);
4357349547db61d2d458b31c074b902d56d082e5d84Jason Sams            if (state == null) return;
43622fa371bf64b8aae786acfe5d711af21afb13a93Jason Sams            state.resumed = true;
437d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            token = state.token;
438d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            readerModeFlags = state.readerModeFlags;
439d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            readerModeExtras = state.readerModeExtras;
4407349547db61d2d458b31c074b902d56d082e5d84Jason Sams        }
4419fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk        if (readerModeFlags != 0) {
442d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            setReaderMode(token, readerModeFlags, readerModeExtras);
443aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
4447349547db61d2d458b31c074b902d56d082e5d84Jason Sams        requestNfcServiceCallback();
445aeb094b520d8ea49b74129927578f18f758c873eJason Sams    }
446aeb094b520d8ea49b74129927578f18f758c873eJason Sams
447aeb094b520d8ea49b74129927578f18f758c873eJason Sams    /** Callback from Activity life-cycle, on main thread */
448aeb094b520d8ea49b74129927578f18f758c873eJason Sams    @Override
449aeb094b520d8ea49b74129927578f18f758c873eJason Sams    public void onActivityPaused(Activity activity) {
450aeb094b520d8ea49b74129927578f18f758c873eJason Sams        boolean readerModeFlagsSet;
451aeb094b520d8ea49b74129927578f18f758c873eJason Sams        Binder token;
452aeb094b520d8ea49b74129927578f18f758c873eJason Sams        synchronized (NfcActivityManager.this) {
453aeb094b520d8ea49b74129927578f18f758c873eJason Sams            NfcActivityState state = findActivityState(activity);
454aeb094b520d8ea49b74129927578f18f758c873eJason Sams            if (DBG) Log.d(TAG, "onPause() for " + activity + " " + state);
455aeb094b520d8ea49b74129927578f18f758c873eJason Sams            if (state == null) return;
456aeb094b520d8ea49b74129927578f18f758c873eJason Sams            state.resumed = false;
457aeb094b520d8ea49b74129927578f18f758c873eJason Sams            token = state.token;
458aeb094b520d8ea49b74129927578f18f758c873eJason Sams            readerModeFlagsSet = state.readerModeFlags != 0;
459aeb094b520d8ea49b74129927578f18f758c873eJason Sams        }
460aeb094b520d8ea49b74129927578f18f758c873eJason Sams        if (readerModeFlagsSet) {
461aeb094b520d8ea49b74129927578f18f758c873eJason Sams            // Restore default p2p modes
462            setReaderMode(token, 0, null);
463        }
464    }
465
466    /** Callback from Activity life-cycle, on main thread */
467    @Override
468    public void onActivityStopped(Activity activity) { /* NO-OP */ }
469
470    /** Callback from Activity life-cycle, on main thread */
471    @Override
472    public void onActivitySaveInstanceState(Activity activity, Bundle outState) { /* NO-OP */ }
473
474    /** Callback from Activity life-cycle, on main thread */
475    @Override
476    public void onActivityDestroyed(Activity activity) {
477        synchronized (NfcActivityManager.this) {
478            NfcActivityState state = findActivityState(activity);
479            if (DBG) Log.d(TAG, "onDestroy() for " + activity + " " + state);
480            if (state != null) {
481                // release all associated references
482                destroyActivityState(activity);
483            }
484        }
485    }
486
487}
488