| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.print; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.content.Context; |
| import android.content.pm.ParceledListSlice; |
| import android.os.Handler; |
| import android.os.Looper; |
| import android.os.Message; |
| import android.os.RemoteException; |
| import android.util.ArrayMap; |
| import android.util.Log; |
| |
| import java.lang.ref.WeakReference; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| |
| /** |
| * @hide |
| */ |
| public final class PrinterDiscoverySession { |
| |
| private static final String LOG_TAG ="PrinterDiscoverySession"; |
| |
| private static final int MSG_PRINTERS_ADDED = 1; |
| private static final int MSG_PRINTERS_REMOVED = 2; |
| |
| private final LinkedHashMap<PrinterId, PrinterInfo> mPrinters = |
| new LinkedHashMap<PrinterId, PrinterInfo>(); |
| |
| private final IPrintManager mPrintManager; |
| |
| private final int mUserId; |
| |
| private final Handler mHandler; |
| |
| private IPrinterDiscoveryObserver mObserver; |
| |
| private OnPrintersChangeListener mListener; |
| |
| private boolean mIsPrinterDiscoveryStarted; |
| |
| public static interface OnPrintersChangeListener { |
| public void onPrintersChanged(); |
| } |
| |
| PrinterDiscoverySession(IPrintManager printManager, Context context, int userId) { |
| mPrintManager = printManager; |
| mUserId = userId; |
| mHandler = new SessionHandler(context.getMainLooper()); |
| mObserver = new PrinterDiscoveryObserver(this); |
| try { |
| mPrintManager.createPrinterDiscoverySession(mObserver, mUserId); |
| } catch (RemoteException re) { |
| Log.e(LOG_TAG, "Error creating printer discovery session", re); |
| } |
| } |
| |
| public final void startPrinterDiscovery(@Nullable List<PrinterId> priorityList) { |
| if (isDestroyed()) { |
| Log.w(LOG_TAG, "Ignoring start printers discovery - session destroyed"); |
| return; |
| } |
| if (!mIsPrinterDiscoveryStarted) { |
| mIsPrinterDiscoveryStarted = true; |
| try { |
| mPrintManager.startPrinterDiscovery(mObserver, priorityList, mUserId); |
| } catch (RemoteException re) { |
| Log.e(LOG_TAG, "Error starting printer discovery", re); |
| } |
| } |
| } |
| |
| public final void stopPrinterDiscovery() { |
| if (isDestroyed()) { |
| Log.w(LOG_TAG, "Ignoring stop printers discovery - session destroyed"); |
| return; |
| } |
| if (mIsPrinterDiscoveryStarted) { |
| mIsPrinterDiscoveryStarted = false; |
| try { |
| mPrintManager.stopPrinterDiscovery(mObserver, mUserId); |
| } catch (RemoteException re) { |
| Log.e(LOG_TAG, "Error stopping printer discovery", re); |
| } |
| } |
| } |
| |
| public final void startPrinterStateTracking(@NonNull PrinterId printerId) { |
| if (isDestroyed()) { |
| Log.w(LOG_TAG, "Ignoring start printer state tracking - session destroyed"); |
| return; |
| } |
| try { |
| mPrintManager.startPrinterStateTracking(printerId, mUserId); |
| } catch (RemoteException re) { |
| Log.e(LOG_TAG, "Error starting printer state tracking", re); |
| } |
| } |
| |
| public final void stopPrinterStateTracking(@NonNull PrinterId printerId) { |
| if (isDestroyed()) { |
| Log.w(LOG_TAG, "Ignoring stop printer state tracking - session destroyed"); |
| return; |
| } |
| try { |
| mPrintManager.stopPrinterStateTracking(printerId, mUserId); |
| } catch (RemoteException re) { |
| Log.e(LOG_TAG, "Error stopping printer state tracking", re); |
| } |
| } |
| |
| public final void validatePrinters(List<PrinterId> printerIds) { |
| if (isDestroyed()) { |
| Log.w(LOG_TAG, "Ignoring validate printers - session destroyed"); |
| return; |
| } |
| try { |
| mPrintManager.validatePrinters(printerIds, mUserId); |
| } catch (RemoteException re) { |
| Log.e(LOG_TAG, "Error validating printers", re); |
| } |
| } |
| |
| public final void destroy() { |
| if (isDestroyed()) { |
| Log.w(LOG_TAG, "Ignoring destroy - session destroyed"); |
| } |
| destroyNoCheck(); |
| } |
| |
| public final List<PrinterInfo> getPrinters() { |
| if (isDestroyed()) { |
| Log.w(LOG_TAG, "Ignoring get printers - session destroyed"); |
| return Collections.emptyList(); |
| } |
| return new ArrayList<PrinterInfo>(mPrinters.values()); |
| } |
| |
| public final boolean isDestroyed() { |
| throwIfNotCalledOnMainThread(); |
| return isDestroyedNoCheck(); |
| } |
| |
| public final boolean isPrinterDiscoveryStarted() { |
| throwIfNotCalledOnMainThread(); |
| return mIsPrinterDiscoveryStarted; |
| } |
| |
| public final void setOnPrintersChangeListener(OnPrintersChangeListener listener) { |
| throwIfNotCalledOnMainThread(); |
| mListener = listener; |
| } |
| |
| @Override |
| protected final void finalize() throws Throwable { |
| if (!isDestroyedNoCheck()) { |
| Log.e(LOG_TAG, "Destroying leaked printer discovery session"); |
| destroyNoCheck(); |
| } |
| super.finalize(); |
| } |
| |
| private boolean isDestroyedNoCheck() { |
| return (mObserver == null); |
| } |
| |
| private void destroyNoCheck() { |
| stopPrinterDiscovery(); |
| try { |
| mPrintManager.destroyPrinterDiscoverySession(mObserver, mUserId); |
| } catch (RemoteException re) { |
| Log.e(LOG_TAG, "Error destroying printer discovery session", re); |
| } finally { |
| mObserver = null; |
| mPrinters.clear(); |
| } |
| } |
| |
| private void handlePrintersAdded(List<PrinterInfo> addedPrinters) { |
| if (isDestroyed()) { |
| return; |
| } |
| |
| // No old printers - do not bother keeping their position. |
| if (mPrinters.isEmpty()) { |
| final int printerCount = addedPrinters.size(); |
| for (int i = 0; i < printerCount; i++) { |
| PrinterInfo printer = addedPrinters.get(i); |
| mPrinters.put(printer.getId(), printer); |
| } |
| notifyOnPrintersChanged(); |
| return; |
| } |
| |
| // Add the printers to a map. |
| ArrayMap<PrinterId, PrinterInfo> addedPrintersMap = |
| new ArrayMap<PrinterId, PrinterInfo>(); |
| final int printerCount = addedPrinters.size(); |
| for (int i = 0; i < printerCount; i++) { |
| PrinterInfo printer = addedPrinters.get(i); |
| addedPrintersMap.put(printer.getId(), printer); |
| } |
| |
| // Update printers we already have. |
| for (PrinterId oldPrinterId : mPrinters.keySet()) { |
| PrinterInfo updatedPrinter = addedPrintersMap.remove(oldPrinterId); |
| if (updatedPrinter != null) { |
| mPrinters.put(oldPrinterId, updatedPrinter); |
| } |
| } |
| |
| // Add the new printers, i.e. what is left. |
| mPrinters.putAll(addedPrintersMap); |
| |
| // Announce the change. |
| notifyOnPrintersChanged(); |
| } |
| |
| private void handlePrintersRemoved(List<PrinterId> printerIds) { |
| if (isDestroyed()) { |
| return; |
| } |
| boolean printersChanged = false; |
| final int removedPrinterIdCount = printerIds.size(); |
| for (int i = 0; i < removedPrinterIdCount; i++) { |
| PrinterId removedPrinterId = printerIds.get(i); |
| if (mPrinters.remove(removedPrinterId) != null) { |
| printersChanged = true; |
| } |
| } |
| if (printersChanged) { |
| notifyOnPrintersChanged(); |
| } |
| } |
| |
| private void notifyOnPrintersChanged() { |
| if (mListener != null) { |
| mListener.onPrintersChanged(); |
| } |
| } |
| |
| private static void throwIfNotCalledOnMainThread() { |
| if (!Looper.getMainLooper().isCurrentThread()) { |
| throw new IllegalAccessError("must be called from the main thread"); |
| } |
| } |
| |
| private final class SessionHandler extends Handler { |
| |
| public SessionHandler(Looper looper) { |
| super(looper, null, false); |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public void handleMessage(Message message) { |
| switch (message.what) { |
| case MSG_PRINTERS_ADDED: { |
| List<PrinterInfo> printers = (List<PrinterInfo>) message.obj; |
| handlePrintersAdded(printers); |
| } break; |
| |
| case MSG_PRINTERS_REMOVED: { |
| List<PrinterId> printerIds = (List<PrinterId>) message.obj; |
| handlePrintersRemoved(printerIds); |
| } break; |
| } |
| } |
| } |
| |
| public static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub { |
| |
| private final WeakReference<PrinterDiscoverySession> mWeakSession; |
| |
| public PrinterDiscoveryObserver(PrinterDiscoverySession session) { |
| mWeakSession = new WeakReference<PrinterDiscoverySession>(session); |
| } |
| |
| @Override |
| @SuppressWarnings("rawtypes") |
| public void onPrintersAdded(ParceledListSlice printers) { |
| PrinterDiscoverySession session = mWeakSession.get(); |
| if (session != null) { |
| session.mHandler.obtainMessage(MSG_PRINTERS_ADDED, |
| printers.getList()).sendToTarget(); |
| } |
| } |
| |
| @Override |
| @SuppressWarnings("rawtypes") |
| public void onPrintersRemoved(ParceledListSlice printerIds) { |
| PrinterDiscoverySession session = mWeakSession.get(); |
| if (session != null) { |
| session.mHandler.obtainMessage(MSG_PRINTERS_REMOVED, |
| printerIds.getList()).sendToTarget(); |
| } |
| } |
| } |
| } |