1a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao/*
2a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Copyright (C) 2010 The Android Open Source Project
3a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao *
4a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * use this file except in compliance with the License. You may obtain a copy of
6a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * the License at
7a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao *
8a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * http://www.apache.org/licenses/LICENSE-2.0
9a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao *
10a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Unless required by applicable law or agreed to in writing, software
11a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * License for the specific language governing permissions and limitations under
14a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * the License.
15a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */
16a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
17a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taopackage com.android.server;
18a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
19d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onukiimport java.io.FileDescriptor;
20d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onukiimport java.io.PrintWriter;
21a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport java.util.HashMap;
22a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
23a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport com.android.server.location.ComprehensiveCountryDetector;
24a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
25a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.content.Context;
26a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.Country;
27a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.CountryListener;
28a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.ICountryDetector;
29a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.ICountryListener;
30a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.os.Handler;
31a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.os.IBinder;
32a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.os.Looper;
33a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.os.Process;
34a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.os.RemoteException;
35d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onukiimport android.util.PrintWriterPrinter;
36d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onukiimport android.util.Printer;
37a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.util.Slog;
38a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
39a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao/**
40a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * This class detects the country that the user is in through
41a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * {@link ComprehensiveCountryDetector}.
42a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao *
43a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * @hide
44a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */
45a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taopublic class CountryDetectorService extends ICountryDetector.Stub implements Runnable {
46a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
47a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
48a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * The class represents the remote listener, it will also removes itself
49a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * from listener list when the remote process was died.
50a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
51a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private final class Receiver implements IBinder.DeathRecipient {
52a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        private final ICountryListener mListener;
53a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        private final IBinder mKey;
54a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
55a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        public Receiver(ICountryListener listener) {
56a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mListener = listener;
57a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mKey = listener.asBinder();
58a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
59a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
60a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        public void binderDied() {
61a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            removeListener(mKey);
62a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
63a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
64a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        @Override
65a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        public boolean equals(Object otherObj) {
66a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            if (otherObj instanceof Receiver) {
67a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                return mKey.equals(((Receiver) otherObj).mKey);
68a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            }
69a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            return false;
70a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
71a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
72a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        @Override
73a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        public int hashCode() {
74a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            return mKey.hashCode();
75a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
76a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
77a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        public ICountryListener getListener() {
78a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            return mListener;
79a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
80a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
81a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
82d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private final static String TAG = "CountryDetector";
83a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
840e87370077b322b3a88c345a44c6bf3d56617071Daniel Lehmann    /** Whether to dump the state of the country detector service to bugreports */
850e87370077b322b3a88c345a44c6bf3d56617071Daniel Lehmann    private static final boolean DEBUG = false;
860e87370077b322b3a88c345a44c6bf3d56617071Daniel Lehmann
87a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private final HashMap<IBinder, Receiver> mReceivers;
88a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private final Context mContext;
89a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private ComprehensiveCountryDetector mCountryDetector;
90a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private boolean mSystemReady;
91a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private Handler mHandler;
92a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private CountryListener mLocationBasedDetectorListener;
93a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
94a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    public CountryDetectorService(Context context) {
95a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        super();
96a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mReceivers = new HashMap<IBinder, Receiver>();
97a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mContext = context;
98a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
99a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
100a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    @Override
101a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    public Country detectCountry() throws RemoteException {
102a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (!mSystemReady) {
103a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            throw new RemoteException();
104a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
105a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return mCountryDetector.detectCountry();
106a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
107a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
108a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
109a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * Add the ICountryListener into the listener list.
110a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
111a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    @Override
112a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    public void addCountryListener(ICountryListener listener) throws RemoteException {
113a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (!mSystemReady) {
114a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            throw new RemoteException();
115a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
116a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        addListener(listener);
117a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
118a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
119a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
120a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * Remove the ICountryListener from the listener list.
121a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
122a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    @Override
123a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    public void removeCountryListener(ICountryListener listener) throws RemoteException {
124a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (!mSystemReady) {
125a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            throw new RemoteException();
126a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
127a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        removeListener(listener.asBinder());
128a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
129a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
130a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private void addListener(ICountryListener listener) {
131a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        synchronized (mReceivers) {
132a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            Receiver r = new Receiver(listener);
133a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            try {
134a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                listener.asBinder().linkToDeath(r, 0);
135a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                mReceivers.put(listener.asBinder(), r);
136a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                if (mReceivers.size() == 1) {
137a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    Slog.d(TAG, "The first listener is added");
138a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    setCountryListener(mLocationBasedDetectorListener);
139a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                }
140a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            } catch (RemoteException e) {
141a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                Slog.e(TAG, "linkToDeath failed:", e);
142a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            }
143a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
144a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
145a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
146a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private void removeListener(IBinder key) {
147a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        synchronized (mReceivers) {
148a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mReceivers.remove(key);
149a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            if (mReceivers.isEmpty()) {
150a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                setCountryListener(null);
151a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                Slog.d(TAG, "No listener is left");
152a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            }
153a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
154a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
155a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
156a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
157a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected void notifyReceivers(Country country) {
158a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        synchronized(mReceivers) {
159a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            for (Receiver receiver : mReceivers.values()) {
160a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                try {
161a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    receiver.getListener().onCountryDetected(country);
162a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                } catch (RemoteException e) {
163a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    // TODO: Shall we remove the receiver?
164a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    Slog.e(TAG, "notifyReceivers failed:", e);
165a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                }
166a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            }
167a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
168a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
169a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
170a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    void systemReady() {
171a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        // Shall we wait for the initialization finish.
172a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        Thread thread = new Thread(this, "CountryDetectorService");
173a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        thread.start();
174a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
175a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
176a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private void initialize() {
177a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mCountryDetector = new ComprehensiveCountryDetector(mContext);
178a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mLocationBasedDetectorListener = new CountryListener() {
179a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            public void onCountryDetected(final Country country) {
180a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                mHandler.post(new Runnable() {
181a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    public void run() {
182a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                        notifyReceivers(country);
183a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    }
184a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                });
185a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            }
186a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        };
187a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
188a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
189a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    public void run() {
190a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
191a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        Looper.prepare();
192a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mHandler = new Handler();
193a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        initialize();
194a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mSystemReady = true;
195a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        Looper.loop();
196a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
197a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
198a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected void setCountryListener(final CountryListener listener) {
199a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mHandler.post(new Runnable() {
200a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            @Override
201a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            public void run() {
202a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                mCountryDetector.setCountryListener(listener);
203a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            }
204a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        });
205a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
206a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
207a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    // For testing
208a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    boolean isSystemReady() {
209a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return mSystemReady;
210a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
211d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
2120e87370077b322b3a88c345a44c6bf3d56617071Daniel Lehmann    @SuppressWarnings("unused")
213d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    @Override
214d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
215eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
216eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey
2170e87370077b322b3a88c345a44c6bf3d56617071Daniel Lehmann        if (!DEBUG) return;
218d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        try {
219d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            final Printer p = new PrintWriterPrinter(fout);
220d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            p.println("CountryDetectorService state:");
221d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            p.println("  Number of listeners=" + mReceivers.keySet().size());
222d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            if (mCountryDetector == null) {
223d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki                p.println("  ComprehensiveCountryDetector not initialized");
224d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            } else {
225d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki                p.println("  " + mCountryDetector.toString());
226d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            }
227d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        } catch (Exception e) {
228d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            Slog.e(TAG, "Failed to dump CountryDetectorService: ", e);
229d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        }
230d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    }
231a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao}
232