137237839e87988208296a57d70767ebbd9c6880bJohn Grossman/*
237237839e87988208296a57d70767ebbd9c6880bJohn Grossman * Copyright (C) 2012 The Android Open Source Project
337237839e87988208296a57d70767ebbd9c6880bJohn Grossman *
437237839e87988208296a57d70767ebbd9c6880bJohn Grossman * Licensed under the Apache License, Version 2.0 (the "License");
537237839e87988208296a57d70767ebbd9c6880bJohn Grossman * you may not use this file except in compliance with the License.
637237839e87988208296a57d70767ebbd9c6880bJohn Grossman * You may obtain a copy of the License at
737237839e87988208296a57d70767ebbd9c6880bJohn Grossman *
837237839e87988208296a57d70767ebbd9c6880bJohn Grossman *      http://www.apache.org/licenses/LICENSE-2.0
937237839e87988208296a57d70767ebbd9c6880bJohn Grossman *
1037237839e87988208296a57d70767ebbd9c6880bJohn Grossman * Unless required by applicable law or agreed to in writing, software
1137237839e87988208296a57d70767ebbd9c6880bJohn Grossman * distributed under the License is distributed on an "AS IS" BASIS,
1237237839e87988208296a57d70767ebbd9c6880bJohn Grossman * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1337237839e87988208296a57d70767ebbd9c6880bJohn Grossman * See the License for the specific language governing permissions and
1437237839e87988208296a57d70767ebbd9c6880bJohn Grossman * limitations under the License.
1537237839e87988208296a57d70767ebbd9c6880bJohn Grossman */
1637237839e87988208296a57d70767ebbd9c6880bJohn Grossmanpackage android.os;
1737237839e87988208296a57d70767ebbd9c6880bJohn Grossman
1837237839e87988208296a57d70767ebbd9c6880bJohn Grossmanimport java.net.InetSocketAddress;
1937237839e87988208296a57d70767ebbd9c6880bJohn Grossmanimport java.util.NoSuchElementException;
2037237839e87988208296a57d70767ebbd9c6880bJohn Grossmanimport android.os.Binder;
2137237839e87988208296a57d70767ebbd9c6880bJohn Grossmanimport android.os.CommonTimeUtils;
2237237839e87988208296a57d70767ebbd9c6880bJohn Grossmanimport android.os.IBinder;
2337237839e87988208296a57d70767ebbd9c6880bJohn Grossmanimport android.os.Parcel;
2437237839e87988208296a57d70767ebbd9c6880bJohn Grossmanimport android.os.RemoteException;
2537237839e87988208296a57d70767ebbd9c6880bJohn Grossmanimport android.os.ServiceManager;
2637237839e87988208296a57d70767ebbd9c6880bJohn Grossman
2737237839e87988208296a57d70767ebbd9c6880bJohn Grossman/**
2837237839e87988208296a57d70767ebbd9c6880bJohn Grossman * Used for accessing the android common time service's common clock and receiving notifications
2937237839e87988208296a57d70767ebbd9c6880bJohn Grossman * about common time synchronization status changes.
3037237839e87988208296a57d70767ebbd9c6880bJohn Grossman * @hide
3137237839e87988208296a57d70767ebbd9c6880bJohn Grossman */
3237237839e87988208296a57d70767ebbd9c6880bJohn Grossmanpublic class CommonClock {
3337237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
3437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Sentinel value returned by {@link #getTime()} and {@link #getEstimatedError()} when the
3537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * common time service is not able to determine the current common time due to a lack of
3637237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * synchronization.
3737237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
3837237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public static final long TIME_NOT_SYNCED = -1;
3937237839e87988208296a57d70767ebbd9c6880bJohn Grossman
4037237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
4137237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Sentinel value returned by {@link #getTimelineId()} when the common time service is not
4237237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * currently synced to any timeline.
4337237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
4437237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public static final long INVALID_TIMELINE_ID = 0;
4537237839e87988208296a57d70767ebbd9c6880bJohn Grossman
4637237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
4737237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Sentinel value returned by {@link #getEstimatedError()} when the common time service is not
4837237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * currently synced to any timeline.
4937237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
5037237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public static final int ERROR_ESTIMATE_UNKNOWN = 0x7FFFFFFF;
5137237839e87988208296a57d70767ebbd9c6880bJohn Grossman
5237237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
5337237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Value used by {@link #getState()} to indicate that there was an internal error while
5437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * attempting to determine the state of the common time service.
5537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
5637237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public static final int STATE_INVALID = -1;
5737237839e87988208296a57d70767ebbd9c6880bJohn Grossman
5837237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
5937237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Value used by {@link #getState()} to indicate that the common time service is in its initial
6037237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * state and attempting to find the current timeline master, if any.  The service will
6137237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * transition to either {@link #STATE_CLIENT} if it finds an active master, or to
6237237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * {@link #STATE_MASTER} if no active master is found and this client becomes the master of a
6337237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * new timeline.
6437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
6537237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public static final int STATE_INITIAL = 0;
6637237839e87988208296a57d70767ebbd9c6880bJohn Grossman
6737237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
6837237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Value used by {@link #getState()} to indicate that the common time service is in its client
6937237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * state and is synchronizing its time to a different timeline master on the network.
7037237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
7137237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public static final int STATE_CLIENT = 1;
7237237839e87988208296a57d70767ebbd9c6880bJohn Grossman
7337237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
7437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Value used by {@link #getState()} to indicate that the common time service is in its master
7537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * state and is serving as the timeline master for other common time service clients on the
7637237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * network.
7737237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
7837237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public static final int STATE_MASTER = 2;
7937237839e87988208296a57d70767ebbd9c6880bJohn Grossman
8037237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
8137237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Value used by {@link #getState()} to indicate that the common time service is in its Ronin
8237237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * state.  Common time service instances in the client state enter the Ronin state after their
8337237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * timeline master becomes unreachable on the network.  Common time services who enter the Ronin
8437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * state will begin a new master election for the timeline they were recently clients of.  As
8537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * clients detect they are not the winner and drop out of the election, they will transition to
8637237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * the {@link #STATE_WAIT_FOR_ELECTION} state.  When there is only one client remaining in the
8737237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * election, it will assume ownership of the timeline and transition to the
8837237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * {@link #STATE_MASTER} state.  During the election, all clients will allow their timeline to
8937237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * drift without applying correction.
9037237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
9137237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public static final int STATE_RONIN = 3;
9237237839e87988208296a57d70767ebbd9c6880bJohn Grossman
9337237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
9437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Value used by {@link #getState()} to indicate that the common time service is waiting for a
9537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * master election to conclude and for the new master to announce itself before transitioning to
9637237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * the {@link #STATE_CLIENT} state.  If no new master announces itself within the timeout
9737237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * threshold, the time service will transition back to the {@link #STATE_RONIN} state in order
9837237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * to restart the election.
9937237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
10037237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public static final int STATE_WAIT_FOR_ELECTION = 4;
10137237839e87988208296a57d70767ebbd9c6880bJohn Grossman
10237237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
10337237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Name of the underlying native binder service
10437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
10537237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public static final String SERVICE_NAME = "common_time.clock";
10637237839e87988208296a57d70767ebbd9c6880bJohn Grossman
10737237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
10837237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Class constructor.
10937237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * @throws android.os.RemoteException
11037237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
11137237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public CommonClock()
11237237839e87988208296a57d70767ebbd9c6880bJohn Grossman    throws RemoteException {
11337237839e87988208296a57d70767ebbd9c6880bJohn Grossman        mRemote = ServiceManager.getService(SERVICE_NAME);
11437237839e87988208296a57d70767ebbd9c6880bJohn Grossman        if (null == mRemote)
11537237839e87988208296a57d70767ebbd9c6880bJohn Grossman            throw new RemoteException();
11637237839e87988208296a57d70767ebbd9c6880bJohn Grossman
11737237839e87988208296a57d70767ebbd9c6880bJohn Grossman        mInterfaceDesc = mRemote.getInterfaceDescriptor();
11837237839e87988208296a57d70767ebbd9c6880bJohn Grossman        mUtils = new CommonTimeUtils(mRemote, mInterfaceDesc);
11937237839e87988208296a57d70767ebbd9c6880bJohn Grossman        mRemote.linkToDeath(mDeathHandler, 0);
12037237839e87988208296a57d70767ebbd9c6880bJohn Grossman        registerTimelineChangeListener();
12137237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
12237237839e87988208296a57d70767ebbd9c6880bJohn Grossman
12337237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
12437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Handy class factory method.
12537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
12637237839e87988208296a57d70767ebbd9c6880bJohn Grossman    static public CommonClock create() {
12737237839e87988208296a57d70767ebbd9c6880bJohn Grossman        CommonClock retVal;
12837237839e87988208296a57d70767ebbd9c6880bJohn Grossman
12937237839e87988208296a57d70767ebbd9c6880bJohn Grossman        try {
13037237839e87988208296a57d70767ebbd9c6880bJohn Grossman            retVal = new CommonClock();
13137237839e87988208296a57d70767ebbd9c6880bJohn Grossman        }
13237237839e87988208296a57d70767ebbd9c6880bJohn Grossman        catch (RemoteException e) {
13337237839e87988208296a57d70767ebbd9c6880bJohn Grossman            retVal = null;
13437237839e87988208296a57d70767ebbd9c6880bJohn Grossman        }
13537237839e87988208296a57d70767ebbd9c6880bJohn Grossman
13637237839e87988208296a57d70767ebbd9c6880bJohn Grossman        return retVal;
13737237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
13837237839e87988208296a57d70767ebbd9c6880bJohn Grossman
13937237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
14037237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Release all native resources held by this {@link android.os.CommonClock} instance.  Once
14137237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * resources have been released, the {@link android.os.CommonClock} instance is disconnected from
14237237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * the native service and will throw a {@link android.os.RemoteException} if any of its
14337237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * methods are called.  Clients should always call release on their client instances before
14437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * releasing their last Java reference to the instance.  Failure to do this will cause
14537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * non-deterministic native resource reclamation and may cause the common time service to remain
14637237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * active on the network for longer than it should.
14737237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
14837237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public void release() {
14937237839e87988208296a57d70767ebbd9c6880bJohn Grossman        unregisterTimelineChangeListener();
15037237839e87988208296a57d70767ebbd9c6880bJohn Grossman        if (null != mRemote) {
15137237839e87988208296a57d70767ebbd9c6880bJohn Grossman            try {
15237237839e87988208296a57d70767ebbd9c6880bJohn Grossman                mRemote.unlinkToDeath(mDeathHandler, 0);
15337237839e87988208296a57d70767ebbd9c6880bJohn Grossman            }
15437237839e87988208296a57d70767ebbd9c6880bJohn Grossman            catch (NoSuchElementException e) { }
15537237839e87988208296a57d70767ebbd9c6880bJohn Grossman            mRemote = null;
15637237839e87988208296a57d70767ebbd9c6880bJohn Grossman        }
15737237839e87988208296a57d70767ebbd9c6880bJohn Grossman        mUtils = null;
15837237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
15937237839e87988208296a57d70767ebbd9c6880bJohn Grossman
16037237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
16137237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Gets the common clock's current time.
16237237839e87988208296a57d70767ebbd9c6880bJohn Grossman     *
16337237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * @return a signed 64-bit value representing the current common time in microseconds, or the
16437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * special value {@link #TIME_NOT_SYNCED} if the common time service is currently not
16537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * synchronized.
16637237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * @throws android.os.RemoteException
16737237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
16837237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public long getTime()
16937237839e87988208296a57d70767ebbd9c6880bJohn Grossman    throws RemoteException {
17037237839e87988208296a57d70767ebbd9c6880bJohn Grossman        throwOnDeadServer();
17137237839e87988208296a57d70767ebbd9c6880bJohn Grossman        return mUtils.transactGetLong(METHOD_GET_COMMON_TIME, TIME_NOT_SYNCED);
17237237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
17337237839e87988208296a57d70767ebbd9c6880bJohn Grossman
17437237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
17537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Gets the current estimation of common clock's synchronization accuracy from the common time
17637237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * service.
17737237839e87988208296a57d70767ebbd9c6880bJohn Grossman     *
17837237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * @return a signed 32-bit value representing the common time service's estimation of
17937237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * synchronization accuracy in microseconds, or the special value
18037237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * {@link #ERROR_ESTIMATE_UNKNOWN} if the common time service is currently not synchronized.
18137237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Negative values indicate that the local server estimates that the nominal common time is
18237237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * behind the local server's time (in other words, the local clock is running fast) Positive
18337237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * values indicate that the local server estimates that the nominal common time is ahead of the
18437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * local server's time (in other words, the local clock is running slow)
18537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * @throws android.os.RemoteException
18637237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
18737237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public int getEstimatedError()
18837237839e87988208296a57d70767ebbd9c6880bJohn Grossman    throws RemoteException {
18937237839e87988208296a57d70767ebbd9c6880bJohn Grossman        throwOnDeadServer();
19037237839e87988208296a57d70767ebbd9c6880bJohn Grossman        return mUtils.transactGetInt(METHOD_GET_ESTIMATED_ERROR, ERROR_ESTIMATE_UNKNOWN);
19137237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
19237237839e87988208296a57d70767ebbd9c6880bJohn Grossman
19337237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
19437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Gets the ID of the timeline the common time service is currently synchronizing its clock to.
19537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     *
19637237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * @return a long representing the unique ID of the timeline the common time service is
19737237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * currently synchronizing with, or {@link #INVALID_TIMELINE_ID} if the common time service is
19837237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * currently not synchronized.
19937237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * @throws android.os.RemoteException
20037237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
20137237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public long getTimelineId()
20237237839e87988208296a57d70767ebbd9c6880bJohn Grossman    throws RemoteException {
20337237839e87988208296a57d70767ebbd9c6880bJohn Grossman        throwOnDeadServer();
20437237839e87988208296a57d70767ebbd9c6880bJohn Grossman        return mUtils.transactGetLong(METHOD_GET_TIMELINE_ID, INVALID_TIMELINE_ID);
20537237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
20637237839e87988208296a57d70767ebbd9c6880bJohn Grossman
20737237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
20837237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Gets the current state of this clock's common time service in the the master election
20937237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * algorithm.
21037237839e87988208296a57d70767ebbd9c6880bJohn Grossman     *
21137237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * @return a integer indicating the current state of the this clock's common time service in the
21237237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * master election algorithm or {@link #STATE_INVALID} if there is an internal error.
21337237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * @throws android.os.RemoteException
21437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
21537237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public int getState()
21637237839e87988208296a57d70767ebbd9c6880bJohn Grossman    throws RemoteException {
21737237839e87988208296a57d70767ebbd9c6880bJohn Grossman        throwOnDeadServer();
21837237839e87988208296a57d70767ebbd9c6880bJohn Grossman        return mUtils.transactGetInt(METHOD_GET_STATE, STATE_INVALID);
21937237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
22037237839e87988208296a57d70767ebbd9c6880bJohn Grossman
22137237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
22237237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Gets the IP address and UDP port of the current timeline master.
22337237839e87988208296a57d70767ebbd9c6880bJohn Grossman     *
22437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * @return an InetSocketAddress containing the IP address and UDP port of the current timeline
22537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * master, or null if there is no current master.
22637237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * @throws android.os.RemoteException
22737237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
22837237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public InetSocketAddress getMasterAddr()
22937237839e87988208296a57d70767ebbd9c6880bJohn Grossman    throws RemoteException {
23037237839e87988208296a57d70767ebbd9c6880bJohn Grossman        throwOnDeadServer();
23137237839e87988208296a57d70767ebbd9c6880bJohn Grossman        return mUtils.transactGetSockaddr(METHOD_GET_MASTER_ADDRESS);
23237237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
23337237839e87988208296a57d70767ebbd9c6880bJohn Grossman
23437237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
23537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * The OnTimelineChangedListener interface defines a method called by the
23637237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * {@link android.os.CommonClock} instance to indicate that the time synchronization service has
23737237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * either synchronized with a new timeline, or is no longer a member of any timeline.  The
23837237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * client application can implement this interface and register the listener with the
23937237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * {@link #setTimelineChangedListener(OnTimelineChangedListener)} method.
24037237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
24137237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public interface OnTimelineChangedListener  {
24237237839e87988208296a57d70767ebbd9c6880bJohn Grossman        /**
24337237839e87988208296a57d70767ebbd9c6880bJohn Grossman         * Method called when the time service's timeline has changed.
24437237839e87988208296a57d70767ebbd9c6880bJohn Grossman         *
24537237839e87988208296a57d70767ebbd9c6880bJohn Grossman         * @param newTimelineId a long which uniquely identifies the timeline the time
24637237839e87988208296a57d70767ebbd9c6880bJohn Grossman         * synchronization service is now a member of, or {@link #INVALID_TIMELINE_ID} if the the
24737237839e87988208296a57d70767ebbd9c6880bJohn Grossman         * service is not synchronized to any timeline.
24837237839e87988208296a57d70767ebbd9c6880bJohn Grossman         */
24937237839e87988208296a57d70767ebbd9c6880bJohn Grossman        void onTimelineChanged(long newTimelineId);
25037237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
25137237839e87988208296a57d70767ebbd9c6880bJohn Grossman
25237237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
25337237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Registers an OnTimelineChangedListener interface.
25437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * <p>Call this method with a null listener to stop receiving server death notifications.
25537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
25637237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public void setTimelineChangedListener(OnTimelineChangedListener listener) {
25737237839e87988208296a57d70767ebbd9c6880bJohn Grossman        synchronized (mListenerLock) {
25837237839e87988208296a57d70767ebbd9c6880bJohn Grossman            mTimelineChangedListener = listener;
25937237839e87988208296a57d70767ebbd9c6880bJohn Grossman        }
26037237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
26137237839e87988208296a57d70767ebbd9c6880bJohn Grossman
26237237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
26337237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * The OnServerDiedListener interface defines a method called by the
26437237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * {@link android.os.CommonClock} instance to indicate that the connection to the native media
26537237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * server has been broken and that the {@link android.os.CommonClock} instance will need to be
26637237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * released and re-created.  The client application can implement this interface and register
26737237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * the listener with the {@link #setServerDiedListener(OnServerDiedListener)} method.
26837237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
26937237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public interface OnServerDiedListener  {
27037237839e87988208296a57d70767ebbd9c6880bJohn Grossman        /**
27137237839e87988208296a57d70767ebbd9c6880bJohn Grossman         * Method called when the native media server has died.  <p>If the native common time
27237237839e87988208296a57d70767ebbd9c6880bJohn Grossman         * service encounters a fatal error and needs to restart, the binder connection from the
27337237839e87988208296a57d70767ebbd9c6880bJohn Grossman         * {@link android.os.CommonClock} instance to the common time service will be broken.  To
27437237839e87988208296a57d70767ebbd9c6880bJohn Grossman         * restore functionality, clients should {@link #release()} their old visualizer and create
27537237839e87988208296a57d70767ebbd9c6880bJohn Grossman         * a new instance.
27637237839e87988208296a57d70767ebbd9c6880bJohn Grossman         */
27737237839e87988208296a57d70767ebbd9c6880bJohn Grossman        void onServerDied();
27837237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
27937237839e87988208296a57d70767ebbd9c6880bJohn Grossman
28037237839e87988208296a57d70767ebbd9c6880bJohn Grossman    /**
28137237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * Registers an OnServerDiedListener interface.
28237237839e87988208296a57d70767ebbd9c6880bJohn Grossman     * <p>Call this method with a null listener to stop receiving server death notifications.
28337237839e87988208296a57d70767ebbd9c6880bJohn Grossman     */
28437237839e87988208296a57d70767ebbd9c6880bJohn Grossman    public void setServerDiedListener(OnServerDiedListener listener) {
28537237839e87988208296a57d70767ebbd9c6880bJohn Grossman        synchronized (mListenerLock) {
28637237839e87988208296a57d70767ebbd9c6880bJohn Grossman            mServerDiedListener = listener;
28737237839e87988208296a57d70767ebbd9c6880bJohn Grossman        }
28837237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
28937237839e87988208296a57d70767ebbd9c6880bJohn Grossman
29037237839e87988208296a57d70767ebbd9c6880bJohn Grossman    protected void finalize() throws Throwable { release(); }
29137237839e87988208296a57d70767ebbd9c6880bJohn Grossman
29237237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private void throwOnDeadServer() throws RemoteException {
29337237839e87988208296a57d70767ebbd9c6880bJohn Grossman        if ((null == mRemote) || (null == mUtils))
29437237839e87988208296a57d70767ebbd9c6880bJohn Grossman            throw new RemoteException();
29537237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
29637237839e87988208296a57d70767ebbd9c6880bJohn Grossman
29737237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private final Object mListenerLock = new Object();
29837237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private OnTimelineChangedListener mTimelineChangedListener = null;
29937237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private OnServerDiedListener mServerDiedListener = null;
30037237839e87988208296a57d70767ebbd9c6880bJohn Grossman
30137237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private IBinder mRemote = null;
30237237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private String mInterfaceDesc = "";
30337237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private CommonTimeUtils mUtils;
30437237839e87988208296a57d70767ebbd9c6880bJohn Grossman
30537237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private IBinder.DeathRecipient mDeathHandler = new IBinder.DeathRecipient() {
30637237839e87988208296a57d70767ebbd9c6880bJohn Grossman        public void binderDied() {
30737237839e87988208296a57d70767ebbd9c6880bJohn Grossman            synchronized (mListenerLock) {
30837237839e87988208296a57d70767ebbd9c6880bJohn Grossman                if (null != mServerDiedListener)
30937237839e87988208296a57d70767ebbd9c6880bJohn Grossman                    mServerDiedListener.onServerDied();
31037237839e87988208296a57d70767ebbd9c6880bJohn Grossman            }
31137237839e87988208296a57d70767ebbd9c6880bJohn Grossman        }
31237237839e87988208296a57d70767ebbd9c6880bJohn Grossman    };
31337237839e87988208296a57d70767ebbd9c6880bJohn Grossman
31437237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private class TimelineChangedListener extends Binder {
31537237839e87988208296a57d70767ebbd9c6880bJohn Grossman        @Override
31637237839e87988208296a57d70767ebbd9c6880bJohn Grossman        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
31737237839e87988208296a57d70767ebbd9c6880bJohn Grossman        throws RemoteException {
31837237839e87988208296a57d70767ebbd9c6880bJohn Grossman            switch (code) {
31937237839e87988208296a57d70767ebbd9c6880bJohn Grossman                case METHOD_CBK_ON_TIMELINE_CHANGED:
32037237839e87988208296a57d70767ebbd9c6880bJohn Grossman                    data.enforceInterface(DESCRIPTOR);
32137237839e87988208296a57d70767ebbd9c6880bJohn Grossman                    long timelineId = data.readLong();
32237237839e87988208296a57d70767ebbd9c6880bJohn Grossman                    synchronized (mListenerLock) {
32337237839e87988208296a57d70767ebbd9c6880bJohn Grossman                        if (null != mTimelineChangedListener)
32437237839e87988208296a57d70767ebbd9c6880bJohn Grossman                            mTimelineChangedListener.onTimelineChanged(timelineId);
32537237839e87988208296a57d70767ebbd9c6880bJohn Grossman                    }
32637237839e87988208296a57d70767ebbd9c6880bJohn Grossman                    return true;
32737237839e87988208296a57d70767ebbd9c6880bJohn Grossman            }
32837237839e87988208296a57d70767ebbd9c6880bJohn Grossman
32937237839e87988208296a57d70767ebbd9c6880bJohn Grossman            return super.onTransact(code, data, reply, flags);
33037237839e87988208296a57d70767ebbd9c6880bJohn Grossman        }
33137237839e87988208296a57d70767ebbd9c6880bJohn Grossman
33237237839e87988208296a57d70767ebbd9c6880bJohn Grossman        private static final String DESCRIPTOR = "android.os.ICommonClockListener";
33337237839e87988208296a57d70767ebbd9c6880bJohn Grossman    };
33437237839e87988208296a57d70767ebbd9c6880bJohn Grossman
33537237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private TimelineChangedListener mCallbackTgt = null;
33637237839e87988208296a57d70767ebbd9c6880bJohn Grossman
33737237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private void registerTimelineChangeListener() throws RemoteException {
33837237839e87988208296a57d70767ebbd9c6880bJohn Grossman        if (null != mCallbackTgt)
33937237839e87988208296a57d70767ebbd9c6880bJohn Grossman            return;
34037237839e87988208296a57d70767ebbd9c6880bJohn Grossman
34137237839e87988208296a57d70767ebbd9c6880bJohn Grossman        boolean success = false;
34237237839e87988208296a57d70767ebbd9c6880bJohn Grossman        android.os.Parcel data  = android.os.Parcel.obtain();
34337237839e87988208296a57d70767ebbd9c6880bJohn Grossman        android.os.Parcel reply = android.os.Parcel.obtain();
34437237839e87988208296a57d70767ebbd9c6880bJohn Grossman        mCallbackTgt = new TimelineChangedListener();
34537237839e87988208296a57d70767ebbd9c6880bJohn Grossman
34637237839e87988208296a57d70767ebbd9c6880bJohn Grossman        try {
34737237839e87988208296a57d70767ebbd9c6880bJohn Grossman            data.writeInterfaceToken(mInterfaceDesc);
34837237839e87988208296a57d70767ebbd9c6880bJohn Grossman            data.writeStrongBinder(mCallbackTgt);
34937237839e87988208296a57d70767ebbd9c6880bJohn Grossman            mRemote.transact(METHOD_REGISTER_LISTENER, data, reply, 0);
35037237839e87988208296a57d70767ebbd9c6880bJohn Grossman            success = (0 == reply.readInt());
35137237839e87988208296a57d70767ebbd9c6880bJohn Grossman        }
35237237839e87988208296a57d70767ebbd9c6880bJohn Grossman        catch (RemoteException e) {
35337237839e87988208296a57d70767ebbd9c6880bJohn Grossman            success = false;
35437237839e87988208296a57d70767ebbd9c6880bJohn Grossman        }
35537237839e87988208296a57d70767ebbd9c6880bJohn Grossman        finally {
35637237839e87988208296a57d70767ebbd9c6880bJohn Grossman            reply.recycle();
35737237839e87988208296a57d70767ebbd9c6880bJohn Grossman            data.recycle();
35837237839e87988208296a57d70767ebbd9c6880bJohn Grossman        }
35937237839e87988208296a57d70767ebbd9c6880bJohn Grossman
36037237839e87988208296a57d70767ebbd9c6880bJohn Grossman        // Did we catch a remote exception or fail to register our callback target?  If so, our
36137237839e87988208296a57d70767ebbd9c6880bJohn Grossman        // object must already be dead (or be as good as dead).  Clear out all of our state so that
36237237839e87988208296a57d70767ebbd9c6880bJohn Grossman        // our other methods will properly indicate a dead object.
36337237839e87988208296a57d70767ebbd9c6880bJohn Grossman        if (!success) {
36437237839e87988208296a57d70767ebbd9c6880bJohn Grossman            mCallbackTgt = null;
36537237839e87988208296a57d70767ebbd9c6880bJohn Grossman            mRemote = null;
36637237839e87988208296a57d70767ebbd9c6880bJohn Grossman            mUtils = null;
36737237839e87988208296a57d70767ebbd9c6880bJohn Grossman        }
36837237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
36937237839e87988208296a57d70767ebbd9c6880bJohn Grossman
37037237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private void unregisterTimelineChangeListener() {
37137237839e87988208296a57d70767ebbd9c6880bJohn Grossman        if (null == mCallbackTgt)
37237237839e87988208296a57d70767ebbd9c6880bJohn Grossman            return;
37337237839e87988208296a57d70767ebbd9c6880bJohn Grossman
37437237839e87988208296a57d70767ebbd9c6880bJohn Grossman        android.os.Parcel data  = android.os.Parcel.obtain();
37537237839e87988208296a57d70767ebbd9c6880bJohn Grossman        android.os.Parcel reply = android.os.Parcel.obtain();
37637237839e87988208296a57d70767ebbd9c6880bJohn Grossman
37737237839e87988208296a57d70767ebbd9c6880bJohn Grossman        try {
37837237839e87988208296a57d70767ebbd9c6880bJohn Grossman            data.writeInterfaceToken(mInterfaceDesc);
37937237839e87988208296a57d70767ebbd9c6880bJohn Grossman            data.writeStrongBinder(mCallbackTgt);
38037237839e87988208296a57d70767ebbd9c6880bJohn Grossman            mRemote.transact(METHOD_UNREGISTER_LISTENER, data, reply, 0);
38137237839e87988208296a57d70767ebbd9c6880bJohn Grossman        }
38237237839e87988208296a57d70767ebbd9c6880bJohn Grossman        catch (RemoteException e) { }
38337237839e87988208296a57d70767ebbd9c6880bJohn Grossman        finally {
38437237839e87988208296a57d70767ebbd9c6880bJohn Grossman            reply.recycle();
38537237839e87988208296a57d70767ebbd9c6880bJohn Grossman            data.recycle();
38637237839e87988208296a57d70767ebbd9c6880bJohn Grossman            mCallbackTgt = null;
38737237839e87988208296a57d70767ebbd9c6880bJohn Grossman        }
38837237839e87988208296a57d70767ebbd9c6880bJohn Grossman    }
38937237839e87988208296a57d70767ebbd9c6880bJohn Grossman
39037237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private static final int METHOD_IS_COMMON_TIME_VALID = IBinder.FIRST_CALL_TRANSACTION;
39137237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private static final int METHOD_COMMON_TIME_TO_LOCAL_TIME = METHOD_IS_COMMON_TIME_VALID + 1;
39237237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private static final int METHOD_LOCAL_TIME_TO_COMMON_TIME = METHOD_COMMON_TIME_TO_LOCAL_TIME + 1;
39337237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private static final int METHOD_GET_COMMON_TIME = METHOD_LOCAL_TIME_TO_COMMON_TIME + 1;
39437237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private static final int METHOD_GET_COMMON_FREQ = METHOD_GET_COMMON_TIME + 1;
39537237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private static final int METHOD_GET_LOCAL_TIME = METHOD_GET_COMMON_FREQ + 1;
39637237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private static final int METHOD_GET_LOCAL_FREQ = METHOD_GET_LOCAL_TIME + 1;
39737237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private static final int METHOD_GET_ESTIMATED_ERROR = METHOD_GET_LOCAL_FREQ + 1;
39837237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private static final int METHOD_GET_TIMELINE_ID = METHOD_GET_ESTIMATED_ERROR + 1;
39937237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private static final int METHOD_GET_STATE = METHOD_GET_TIMELINE_ID + 1;
40037237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private static final int METHOD_GET_MASTER_ADDRESS = METHOD_GET_STATE + 1;
40137237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private static final int METHOD_REGISTER_LISTENER = METHOD_GET_MASTER_ADDRESS + 1;
40237237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private static final int METHOD_UNREGISTER_LISTENER = METHOD_REGISTER_LISTENER + 1;
40337237839e87988208296a57d70767ebbd9c6880bJohn Grossman
40437237839e87988208296a57d70767ebbd9c6880bJohn Grossman    private static final int METHOD_CBK_ON_TIMELINE_CHANGED = IBinder.FIRST_CALL_TRANSACTION;
40537237839e87988208296a57d70767ebbd9c6880bJohn Grossman}
406