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
1976d7e3ee70c4299b22b1a03505d2b4f108716c75Philip P. Moltmannimport android.annotation.NonNull;
2076d7e3ee70c4299b22b1a03505d2b4f108716c75Philip P. Moltmannimport android.annotation.Nullable;
2144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.content.Context;
222fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport android.content.pm.ParceledListSlice;
2344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.os.Handler;
2444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.os.Looper;
2544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.os.Message;
2644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.os.RemoteException;
2744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.util.ArrayMap;
2844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.util.Log;
2944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
3044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport java.lang.ref.WeakReference;
3144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport java.util.ArrayList;
3244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport java.util.Collections;
33cfab2457f2c140a2356bb45ec25f51a0a5866556Svetoslav Ganovimport java.util.LinkedHashMap;
3444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport java.util.List;
3544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
3644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov/**
3744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov * @hide
3844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov */
3944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovpublic final class PrinterDiscoverySession {
4044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
4144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private static final String LOG_TAG ="PrinterDiscoverySession";
4244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
4344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private static final int MSG_PRINTERS_ADDED = 1;
4444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private static final int MSG_PRINTERS_REMOVED = 2;
4544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
46cfab2457f2c140a2356bb45ec25f51a0a5866556Svetoslav Ganov    private final LinkedHashMap<PrinterId, PrinterInfo> mPrinters =
47cfab2457f2c140a2356bb45ec25f51a0a5866556Svetoslav Ganov            new LinkedHashMap<PrinterId, PrinterInfo>();
4844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
4944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private final IPrintManager mPrintManager;
5044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
5144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private final int mUserId;
5244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
5344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private final Handler mHandler;
5444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
5544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private IPrinterDiscoveryObserver mObserver;
5644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
5744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private OnPrintersChangeListener mListener;
5844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
5944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private boolean mIsPrinterDiscoveryStarted;
6044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
6144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public static interface OnPrintersChangeListener {
6244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public void onPrintersChanged();
6344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
6444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
6544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    PrinterDiscoverySession(IPrintManager printManager, Context context, int userId) {
6644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        mPrintManager = printManager;
6744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        mUserId = userId;
6844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        mHandler = new SessionHandler(context.getMainLooper());
6944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        mObserver = new PrinterDiscoveryObserver(this);
7044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        try {
7144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mPrintManager.createPrinterDiscoverySession(mObserver, mUserId);
7244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } catch (RemoteException re) {
7344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Log.e(LOG_TAG, "Error creating printer discovery session", re);
7444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
7544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
7644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
7776d7e3ee70c4299b22b1a03505d2b4f108716c75Philip P. Moltmann    public final void startPrinterDiscovery(@Nullable List<PrinterId> priorityList) {
7844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (isDestroyed()) {
79a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav            Log.w(LOG_TAG, "Ignoring start printers discovery - session destroyed");
80d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            return;
8144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
8244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (!mIsPrinterDiscoveryStarted) {
8344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mIsPrinterDiscoveryStarted = true;
8444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            try {
8544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                mPrintManager.startPrinterDiscovery(mObserver, priorityList, mUserId);
8644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            } catch (RemoteException re) {
8744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Log.e(LOG_TAG, "Error starting printer discovery", re);
8844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
8944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
9044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
9144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
9244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public final void stopPrinterDiscovery() {
9344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (isDestroyed()) {
9444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Log.w(LOG_TAG, "Ignoring stop printers discovery - session destroyed");
95d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            return;
9644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
9744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (mIsPrinterDiscoveryStarted) {
9844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mIsPrinterDiscoveryStarted = false;
9944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            try {
10044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                mPrintManager.stopPrinterDiscovery(mObserver, mUserId);
10144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            } catch (RemoteException re) {
10244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Log.e(LOG_TAG, "Error stopping printer discovery", re);
10344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
10444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
10544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
10644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
10776d7e3ee70c4299b22b1a03505d2b4f108716c75Philip P. Moltmann    public final void startPrinterStateTracking(@NonNull PrinterId printerId) {
10844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (isDestroyed()) {
109d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Log.w(LOG_TAG, "Ignoring start printer state tracking - session destroyed");
110d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            return;
11144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
11244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        try {
113d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            mPrintManager.startPrinterStateTracking(printerId, mUserId);
11444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } catch (RemoteException re) {
115d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Log.e(LOG_TAG, "Error starting printer state tracking", re);
116d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
117d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    }
118d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
11976d7e3ee70c4299b22b1a03505d2b4f108716c75Philip P. Moltmann    public final void stopPrinterStateTracking(@NonNull PrinterId printerId) {
120d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        if (isDestroyed()) {
121d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Log.w(LOG_TAG, "Ignoring stop printer state tracking - session destroyed");
122d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            return;
123d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
124d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        try {
125d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            mPrintManager.stopPrinterStateTracking(printerId, mUserId);
126d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        } catch (RemoteException re) {
127a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav            Log.e(LOG_TAG, "Error stopping printer state tracking", re);
128d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
129d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    }
130d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
131d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    public final void validatePrinters(List<PrinterId> printerIds) {
132d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        if (isDestroyed()) {
133d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Log.w(LOG_TAG, "Ignoring validate printers - session destroyed");
134d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            return;
135d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
136d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        try {
137d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            mPrintManager.validatePrinters(printerIds, mUserId);
138d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        } catch (RemoteException re) {
139d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Log.e(LOG_TAG, "Error validating printers", re);
14044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
14144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
14244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
14344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public final void destroy() {
14444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (isDestroyed()) {
14544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Log.w(LOG_TAG, "Ignoring destroy - session destroyed");
14644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
14744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        destroyNoCheck();
14844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
14944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
15044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public final List<PrinterInfo> getPrinters() {
15144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (isDestroyed()) {
15244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Log.w(LOG_TAG, "Ignoring get printers - session destroyed");
15344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            return Collections.emptyList();
15444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
15544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        return new ArrayList<PrinterInfo>(mPrinters.values());
15644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
15744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
15844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public final boolean isDestroyed() {
15944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        throwIfNotCalledOnMainThread();
16044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        return isDestroyedNoCheck();
16144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
16244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
16344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public final boolean isPrinterDiscoveryStarted() {
16444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        throwIfNotCalledOnMainThread();
16544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        return mIsPrinterDiscoveryStarted;
16644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
16744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
16844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public final void setOnPrintersChangeListener(OnPrintersChangeListener listener) {
16944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        throwIfNotCalledOnMainThread();
17044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        mListener = listener;
17144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
17244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
17344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    @Override
17444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    protected final void finalize() throws Throwable {
17544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (!isDestroyedNoCheck()) {
17644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Log.e(LOG_TAG, "Destroying leaked printer discovery session");
17744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            destroyNoCheck();
17844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
17944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        super.finalize();
18044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
18144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
18244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private boolean isDestroyedNoCheck() {
18344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        return (mObserver == null);
18444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
18544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
18644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private void destroyNoCheck() {
18744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        stopPrinterDiscovery();
18844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        try {
18944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mPrintManager.destroyPrinterDiscoverySession(mObserver, mUserId);
19044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } catch (RemoteException re) {
19144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Log.e(LOG_TAG, "Error destroying printer discovery session", re);
19244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } finally {
19344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mObserver = null;
19444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mPrinters.clear();
19544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
19644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
19744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
198c335eb411503154cf475903eb6c5c67575769112Svetoslav    private void handlePrintersAdded(List<PrinterInfo> addedPrinters) {
19944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (isDestroyed()) {
20044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            return;
20144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
202c335eb411503154cf475903eb6c5c67575769112Svetoslav
203c335eb411503154cf475903eb6c5c67575769112Svetoslav        // No old printers - do not bother keeping their position.
204c335eb411503154cf475903eb6c5c67575769112Svetoslav        if (mPrinters.isEmpty()) {
205c335eb411503154cf475903eb6c5c67575769112Svetoslav            final int printerCount = addedPrinters.size();
206c335eb411503154cf475903eb6c5c67575769112Svetoslav            for (int i = 0; i < printerCount; i++) {
207c335eb411503154cf475903eb6c5c67575769112Svetoslav                PrinterInfo printer = addedPrinters.get(i);
208c335eb411503154cf475903eb6c5c67575769112Svetoslav                mPrinters.put(printer.getId(), printer);
20944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
21044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            notifyOnPrintersChanged();
211c335eb411503154cf475903eb6c5c67575769112Svetoslav            return;
21244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
213c335eb411503154cf475903eb6c5c67575769112Svetoslav
214c335eb411503154cf475903eb6c5c67575769112Svetoslav        // Add the printers to a map.
215c335eb411503154cf475903eb6c5c67575769112Svetoslav        ArrayMap<PrinterId, PrinterInfo> addedPrintersMap =
216c335eb411503154cf475903eb6c5c67575769112Svetoslav                new ArrayMap<PrinterId, PrinterInfo>();
217c335eb411503154cf475903eb6c5c67575769112Svetoslav        final int printerCount = addedPrinters.size();
218c335eb411503154cf475903eb6c5c67575769112Svetoslav        for (int i = 0; i < printerCount; i++) {
219c335eb411503154cf475903eb6c5c67575769112Svetoslav            PrinterInfo printer = addedPrinters.get(i);
220c335eb411503154cf475903eb6c5c67575769112Svetoslav            addedPrintersMap.put(printer.getId(), printer);
221c335eb411503154cf475903eb6c5c67575769112Svetoslav        }
222c335eb411503154cf475903eb6c5c67575769112Svetoslav
223c335eb411503154cf475903eb6c5c67575769112Svetoslav        // Update printers we already have.
224cfab2457f2c140a2356bb45ec25f51a0a5866556Svetoslav Ganov        for (PrinterId oldPrinterId : mPrinters.keySet()) {
225c335eb411503154cf475903eb6c5c67575769112Svetoslav            PrinterInfo updatedPrinter = addedPrintersMap.remove(oldPrinterId);
226c335eb411503154cf475903eb6c5c67575769112Svetoslav            if (updatedPrinter != null) {
227c335eb411503154cf475903eb6c5c67575769112Svetoslav                mPrinters.put(oldPrinterId, updatedPrinter);
228c335eb411503154cf475903eb6c5c67575769112Svetoslav            }
229c335eb411503154cf475903eb6c5c67575769112Svetoslav        }
230c335eb411503154cf475903eb6c5c67575769112Svetoslav
231c335eb411503154cf475903eb6c5c67575769112Svetoslav        // Add the new printers, i.e. what is left.
232c335eb411503154cf475903eb6c5c67575769112Svetoslav        mPrinters.putAll(addedPrintersMap);
233c335eb411503154cf475903eb6c5c67575769112Svetoslav
234c335eb411503154cf475903eb6c5c67575769112Svetoslav        // Announce the change.
235c335eb411503154cf475903eb6c5c67575769112Svetoslav        notifyOnPrintersChanged();
23644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
23744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
23844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private void handlePrintersRemoved(List<PrinterId> printerIds) {
23944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (isDestroyed()) {
24044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            return;
24144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
24244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        boolean printersChanged = false;
24344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final int removedPrinterIdCount = printerIds.size();
24444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        for (int i = 0; i < removedPrinterIdCount; i++) {
24544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            PrinterId removedPrinterId = printerIds.get(i);
24644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mPrinters.remove(removedPrinterId) != null) {
24744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                printersChanged = true;
24844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
24944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
25044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (printersChanged) {
25144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            notifyOnPrintersChanged();
25244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
25344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
25444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
25544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private void notifyOnPrintersChanged() {
25644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (mListener != null) {
25744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mListener.onPrintersChanged();
25844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
25944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
26044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
26144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private static void throwIfNotCalledOnMainThread() {
26244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (!Looper.getMainLooper().isCurrentThread()) {
26344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            throw new IllegalAccessError("must be called from the main thread");
26444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
26544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
26644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
26744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private final class SessionHandler extends Handler {
26844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
26944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public SessionHandler(Looper looper) {
27044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            super(looper, null, false);
27144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
27244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
27344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        @Override
27444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        @SuppressWarnings("unchecked")
27544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public void handleMessage(Message message) {
27644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            switch (message.what) {
27744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                case MSG_PRINTERS_ADDED: {
27844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
27944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    handlePrintersAdded(printers);
28044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                } break;
28144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
28244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                case MSG_PRINTERS_REMOVED: {
28344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    List<PrinterId> printerIds = (List<PrinterId>) message.obj;
28444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    handlePrintersRemoved(printerIds);
28544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                } break;
28644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
28744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
28844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
28944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
29076d7e3ee70c4299b22b1a03505d2b4f108716c75Philip P. Moltmann    public static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
29144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
29244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private final WeakReference<PrinterDiscoverySession> mWeakSession;
29344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
29444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public PrinterDiscoveryObserver(PrinterDiscoverySession session) {
29544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mWeakSession = new WeakReference<PrinterDiscoverySession>(session);
29644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
29744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
29844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        @Override
2992fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        @SuppressWarnings("rawtypes")
3002fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        public void onPrintersAdded(ParceledListSlice printers) {
30144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            PrinterDiscoverySession session = mWeakSession.get();
30244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (session != null) {
30344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                session.mHandler.obtainMessage(MSG_PRINTERS_ADDED,
3042fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        printers.getList()).sendToTarget();
30544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
30644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
30744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
30844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        @Override
3092fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        @SuppressWarnings("rawtypes")
3102fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        public void onPrintersRemoved(ParceledListSlice printerIds) {
31144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            PrinterDiscoverySession session = mWeakSession.get();
31244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (session != null) {
31344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                session.mHandler.obtainMessage(MSG_PRINTERS_REMOVED,
3142fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        printerIds.getList()).sendToTarget();
31544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
31644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
31744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
31844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov}
319