144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov/*
244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov * Copyright (C) 2013 The Android Open Source Project
344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov *
444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License");
544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov * you may not use this file except in compliance with the License.
644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov * You may obtain a copy of the License at
744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov *
844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov *      http://www.apache.org/licenses/LICENSE-2.0
944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov *
1044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov * Unless required by applicable law or agreed to in writing, software
1144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS,
1244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov * See the License for the specific language governing permissions and
1444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov * limitations under the License.
1544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov */
1644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
1744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovpackage android.print;
1844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
1944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.content.Context;
202fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport android.content.pm.ParceledListSlice;
2144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.os.Handler;
2244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.os.Looper;
2344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.os.Message;
2444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.os.RemoteException;
2544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.util.ArrayMap;
2644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.util.Log;
2744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
2844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport java.lang.ref.WeakReference;
2944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport java.util.ArrayList;
3044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport java.util.Collections;
31cfab2457f2c140a2356bb45ec25f51a0a5866556Svetoslav Ganovimport java.util.LinkedHashMap;
3244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport java.util.List;
3344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
3444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov/**
3544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov * @hide
3644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov */
3744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovpublic final class PrinterDiscoverySession {
3844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
3944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private static final String LOG_TAG ="PrinterDiscoverySession";
4044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
4144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private static final int MSG_PRINTERS_ADDED = 1;
4244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private static final int MSG_PRINTERS_REMOVED = 2;
4344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
44cfab2457f2c140a2356bb45ec25f51a0a5866556Svetoslav Ganov    private final LinkedHashMap<PrinterId, PrinterInfo> mPrinters =
45cfab2457f2c140a2356bb45ec25f51a0a5866556Svetoslav Ganov            new LinkedHashMap<PrinterId, PrinterInfo>();
4644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
4744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private final IPrintManager mPrintManager;
4844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
4944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private final int mUserId;
5044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
5144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private final Handler mHandler;
5244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
5344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private IPrinterDiscoveryObserver mObserver;
5444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
5544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private OnPrintersChangeListener mListener;
5644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
5744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private boolean mIsPrinterDiscoveryStarted;
5844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
5944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public static interface OnPrintersChangeListener {
6044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public void onPrintersChanged();
6144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
6244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
6344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    PrinterDiscoverySession(IPrintManager printManager, Context context, int userId) {
6444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        mPrintManager = printManager;
6544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        mUserId = userId;
6644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        mHandler = new SessionHandler(context.getMainLooper());
6744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        mObserver = new PrinterDiscoveryObserver(this);
6844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        try {
6944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mPrintManager.createPrinterDiscoverySession(mObserver, mUserId);
7044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } catch (RemoteException re) {
7144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Log.e(LOG_TAG, "Error creating printer discovery session", re);
7244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
7344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
7444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
75a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav    public final void startPrinterDiscovery(List<PrinterId> priorityList) {
7644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (isDestroyed()) {
77a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav            Log.w(LOG_TAG, "Ignoring start printers discovery - session destroyed");
78d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            return;
7944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
8044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (!mIsPrinterDiscoveryStarted) {
8144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mIsPrinterDiscoveryStarted = true;
8244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            try {
8344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                mPrintManager.startPrinterDiscovery(mObserver, priorityList, mUserId);
8444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            } catch (RemoteException re) {
8544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Log.e(LOG_TAG, "Error starting printer discovery", re);
8644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
8744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
8844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
8944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
9044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public final void stopPrinterDiscovery() {
9144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (isDestroyed()) {
9244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Log.w(LOG_TAG, "Ignoring stop printers discovery - session destroyed");
93d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            return;
9444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
9544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (mIsPrinterDiscoveryStarted) {
9644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mIsPrinterDiscoveryStarted = false;
9744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            try {
9844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                mPrintManager.stopPrinterDiscovery(mObserver, mUserId);
9944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            } catch (RemoteException re) {
10044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Log.e(LOG_TAG, "Error stopping printer discovery", re);
10144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
10244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
10344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
10444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
105d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    public final void startPrinterStateTracking(PrinterId printerId) {
10644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (isDestroyed()) {
107d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Log.w(LOG_TAG, "Ignoring start printer state tracking - session destroyed");
108d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            return;
10944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
11044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        try {
111d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            mPrintManager.startPrinterStateTracking(printerId, mUserId);
11244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } catch (RemoteException re) {
113d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Log.e(LOG_TAG, "Error starting printer state tracking", re);
114d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
115d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    }
116d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
117d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    public final void stopPrinterStateTracking(PrinterId printerId) {
118d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        if (isDestroyed()) {
119d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Log.w(LOG_TAG, "Ignoring stop printer state tracking - session destroyed");
120d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            return;
121d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
122d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        try {
123d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            mPrintManager.stopPrinterStateTracking(printerId, mUserId);
124d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        } catch (RemoteException re) {
125a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav            Log.e(LOG_TAG, "Error stopping printer state tracking", re);
126d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
127d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    }
128d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
129d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    public final void validatePrinters(List<PrinterId> printerIds) {
130d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        if (isDestroyed()) {
131d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Log.w(LOG_TAG, "Ignoring validate printers - session destroyed");
132d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            return;
133d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
134d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        try {
135d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            mPrintManager.validatePrinters(printerIds, mUserId);
136d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        } catch (RemoteException re) {
137d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Log.e(LOG_TAG, "Error validating printers", re);
13844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
13944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
14044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
14144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public final void destroy() {
14244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (isDestroyed()) {
14344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Log.w(LOG_TAG, "Ignoring destroy - session destroyed");
14444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
14544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        destroyNoCheck();
14644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
14744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
14844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public final List<PrinterInfo> getPrinters() {
14944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (isDestroyed()) {
15044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Log.w(LOG_TAG, "Ignoring get printers - session destroyed");
15144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            return Collections.emptyList();
15244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
15344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        return new ArrayList<PrinterInfo>(mPrinters.values());
15444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
15544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
15644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public final boolean isDestroyed() {
15744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        throwIfNotCalledOnMainThread();
15844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        return isDestroyedNoCheck();
15944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
16044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
16144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public final boolean isPrinterDiscoveryStarted() {
16244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        throwIfNotCalledOnMainThread();
16344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        return mIsPrinterDiscoveryStarted;
16444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
16544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
16644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public final void setOnPrintersChangeListener(OnPrintersChangeListener listener) {
16744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        throwIfNotCalledOnMainThread();
16844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        mListener = listener;
16944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
17044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
17144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    @Override
17244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    protected final void finalize() throws Throwable {
17344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (!isDestroyedNoCheck()) {
17444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Log.e(LOG_TAG, "Destroying leaked printer discovery session");
17544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            destroyNoCheck();
17644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
17744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        super.finalize();
17844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
17944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
18044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private boolean isDestroyedNoCheck() {
18144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        return (mObserver == null);
18244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
18344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
18444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private void destroyNoCheck() {
18544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        stopPrinterDiscovery();
18644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        try {
18744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mPrintManager.destroyPrinterDiscoverySession(mObserver, mUserId);
18844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } catch (RemoteException re) {
18944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Log.e(LOG_TAG, "Error destroying printer discovery session", re);
19044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } finally {
19144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mObserver = null;
19244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mPrinters.clear();
19344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
19444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
19544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
196c335eb411503154cf475903eb6c5c67575769112Svetoslav    private void handlePrintersAdded(List<PrinterInfo> addedPrinters) {
19744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (isDestroyed()) {
19844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            return;
19944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
200c335eb411503154cf475903eb6c5c67575769112Svetoslav
201c335eb411503154cf475903eb6c5c67575769112Svetoslav        // No old printers - do not bother keeping their position.
202c335eb411503154cf475903eb6c5c67575769112Svetoslav        if (mPrinters.isEmpty()) {
203c335eb411503154cf475903eb6c5c67575769112Svetoslav            final int printerCount = addedPrinters.size();
204c335eb411503154cf475903eb6c5c67575769112Svetoslav            for (int i = 0; i < printerCount; i++) {
205c335eb411503154cf475903eb6c5c67575769112Svetoslav                PrinterInfo printer = addedPrinters.get(i);
206c335eb411503154cf475903eb6c5c67575769112Svetoslav                mPrinters.put(printer.getId(), printer);
20744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
20844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            notifyOnPrintersChanged();
209c335eb411503154cf475903eb6c5c67575769112Svetoslav            return;
21044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
211c335eb411503154cf475903eb6c5c67575769112Svetoslav
212c335eb411503154cf475903eb6c5c67575769112Svetoslav        // Add the printers to a map.
213c335eb411503154cf475903eb6c5c67575769112Svetoslav        ArrayMap<PrinterId, PrinterInfo> addedPrintersMap =
214c335eb411503154cf475903eb6c5c67575769112Svetoslav                new ArrayMap<PrinterId, PrinterInfo>();
215c335eb411503154cf475903eb6c5c67575769112Svetoslav        final int printerCount = addedPrinters.size();
216c335eb411503154cf475903eb6c5c67575769112Svetoslav        for (int i = 0; i < printerCount; i++) {
217c335eb411503154cf475903eb6c5c67575769112Svetoslav            PrinterInfo printer = addedPrinters.get(i);
218c335eb411503154cf475903eb6c5c67575769112Svetoslav            addedPrintersMap.put(printer.getId(), printer);
219c335eb411503154cf475903eb6c5c67575769112Svetoslav        }
220c335eb411503154cf475903eb6c5c67575769112Svetoslav
221c335eb411503154cf475903eb6c5c67575769112Svetoslav        // Update printers we already have.
222cfab2457f2c140a2356bb45ec25f51a0a5866556Svetoslav Ganov        for (PrinterId oldPrinterId : mPrinters.keySet()) {
223c335eb411503154cf475903eb6c5c67575769112Svetoslav            PrinterInfo updatedPrinter = addedPrintersMap.remove(oldPrinterId);
224c335eb411503154cf475903eb6c5c67575769112Svetoslav            if (updatedPrinter != null) {
225c335eb411503154cf475903eb6c5c67575769112Svetoslav                mPrinters.put(oldPrinterId, updatedPrinter);
226c335eb411503154cf475903eb6c5c67575769112Svetoslav            }
227c335eb411503154cf475903eb6c5c67575769112Svetoslav        }
228c335eb411503154cf475903eb6c5c67575769112Svetoslav
229c335eb411503154cf475903eb6c5c67575769112Svetoslav        // Add the new printers, i.e. what is left.
230c335eb411503154cf475903eb6c5c67575769112Svetoslav        mPrinters.putAll(addedPrintersMap);
231c335eb411503154cf475903eb6c5c67575769112Svetoslav
232c335eb411503154cf475903eb6c5c67575769112Svetoslav        // Announce the change.
233c335eb411503154cf475903eb6c5c67575769112Svetoslav        notifyOnPrintersChanged();
23444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
23544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
23644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private void handlePrintersRemoved(List<PrinterId> printerIds) {
23744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (isDestroyed()) {
23844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            return;
23944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
24044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        boolean printersChanged = false;
24144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final int removedPrinterIdCount = printerIds.size();
24244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        for (int i = 0; i < removedPrinterIdCount; i++) {
24344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            PrinterId removedPrinterId = printerIds.get(i);
24444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mPrinters.remove(removedPrinterId) != null) {
24544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                printersChanged = true;
24644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
24744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
24844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (printersChanged) {
24944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            notifyOnPrintersChanged();
25044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
25144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
25244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
25344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private void notifyOnPrintersChanged() {
25444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (mListener != null) {
25544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mListener.onPrintersChanged();
25644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
25744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
25844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
25944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private static void throwIfNotCalledOnMainThread() {
26044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (!Looper.getMainLooper().isCurrentThread()) {
26144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            throw new IllegalAccessError("must be called from the main thread");
26244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
26344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
26444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
26544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private final class SessionHandler extends Handler {
26644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
26744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public SessionHandler(Looper looper) {
26844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            super(looper, null, false);
26944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
27044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
27144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        @Override
27244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        @SuppressWarnings("unchecked")
27344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public void handleMessage(Message message) {
27444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            switch (message.what) {
27544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                case MSG_PRINTERS_ADDED: {
27644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
27744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    handlePrintersAdded(printers);
27844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                } break;
27944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
28044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                case MSG_PRINTERS_REMOVED: {
28144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    List<PrinterId> printerIds = (List<PrinterId>) message.obj;
28244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    handlePrintersRemoved(printerIds);
28344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                } break;
28444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
28544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
28644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
28744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
28844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
28944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
29044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private final WeakReference<PrinterDiscoverySession> mWeakSession;
29144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
29244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public PrinterDiscoveryObserver(PrinterDiscoverySession session) {
29344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mWeakSession = new WeakReference<PrinterDiscoverySession>(session);
29444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
29544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
29644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        @Override
2972fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        @SuppressWarnings("rawtypes")
2982fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        public void onPrintersAdded(ParceledListSlice printers) {
29944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            PrinterDiscoverySession session = mWeakSession.get();
30044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (session != null) {
30144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                session.mHandler.obtainMessage(MSG_PRINTERS_ADDED,
3022fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        printers.getList()).sendToTarget();
30344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
30444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
30544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
30644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        @Override
3072fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        @SuppressWarnings("rawtypes")
3082fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        public void onPrintersRemoved(ParceledListSlice printerIds) {
30944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            PrinterDiscoverySession session = mWeakSession.get();
31044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (session != null) {
31144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                session.mHandler.obtainMessage(MSG_PRINTERS_REMOVED,
3122fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        printerIds.getList()).sendToTarget();
31344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
31444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
31544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
31644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov}
317