Home | History | Annotate | Download | only in print
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.print;
     18 
     19 import android.annotation.NonNull;
     20 import android.annotation.Nullable;
     21 import android.content.Context;
     22 import android.content.pm.ParceledListSlice;
     23 import android.os.Handler;
     24 import android.os.Looper;
     25 import android.os.Message;
     26 import android.os.RemoteException;
     27 import android.util.ArrayMap;
     28 import android.util.Log;
     29 
     30 import java.lang.ref.WeakReference;
     31 import java.util.ArrayList;
     32 import java.util.Collections;
     33 import java.util.LinkedHashMap;
     34 import java.util.List;
     35 
     36 /**
     37  * @hide
     38  */
     39 public final class PrinterDiscoverySession {
     40 
     41     private static final String LOG_TAG ="PrinterDiscoverySession";
     42 
     43     private static final int MSG_PRINTERS_ADDED = 1;
     44     private static final int MSG_PRINTERS_REMOVED = 2;
     45 
     46     private final LinkedHashMap<PrinterId, PrinterInfo> mPrinters =
     47             new LinkedHashMap<PrinterId, PrinterInfo>();
     48 
     49     private final IPrintManager mPrintManager;
     50 
     51     private final int mUserId;
     52 
     53     private final Handler mHandler;
     54 
     55     private IPrinterDiscoveryObserver mObserver;
     56 
     57     private OnPrintersChangeListener mListener;
     58 
     59     private boolean mIsPrinterDiscoveryStarted;
     60 
     61     public static interface OnPrintersChangeListener {
     62         public void onPrintersChanged();
     63     }
     64 
     65     PrinterDiscoverySession(IPrintManager printManager, Context context, int userId) {
     66         mPrintManager = printManager;
     67         mUserId = userId;
     68         mHandler = new SessionHandler(context.getMainLooper());
     69         mObserver = new PrinterDiscoveryObserver(this);
     70         try {
     71             mPrintManager.createPrinterDiscoverySession(mObserver, mUserId);
     72         } catch (RemoteException re) {
     73             Log.e(LOG_TAG, "Error creating printer discovery session", re);
     74         }
     75     }
     76 
     77     public final void startPrinterDiscovery(@Nullable List<PrinterId> priorityList) {
     78         if (isDestroyed()) {
     79             Log.w(LOG_TAG, "Ignoring start printers discovery - session destroyed");
     80             return;
     81         }
     82         if (!mIsPrinterDiscoveryStarted) {
     83             mIsPrinterDiscoveryStarted = true;
     84             try {
     85                 mPrintManager.startPrinterDiscovery(mObserver, priorityList, mUserId);
     86             } catch (RemoteException re) {
     87                 Log.e(LOG_TAG, "Error starting printer discovery", re);
     88             }
     89         }
     90     }
     91 
     92     public final void stopPrinterDiscovery() {
     93         if (isDestroyed()) {
     94             Log.w(LOG_TAG, "Ignoring stop printers discovery - session destroyed");
     95             return;
     96         }
     97         if (mIsPrinterDiscoveryStarted) {
     98             mIsPrinterDiscoveryStarted = false;
     99             try {
    100                 mPrintManager.stopPrinterDiscovery(mObserver, mUserId);
    101             } catch (RemoteException re) {
    102                 Log.e(LOG_TAG, "Error stopping printer discovery", re);
    103             }
    104         }
    105     }
    106 
    107     public final void startPrinterStateTracking(@NonNull PrinterId printerId) {
    108         if (isDestroyed()) {
    109             Log.w(LOG_TAG, "Ignoring start printer state tracking - session destroyed");
    110             return;
    111         }
    112         try {
    113             mPrintManager.startPrinterStateTracking(printerId, mUserId);
    114         } catch (RemoteException re) {
    115             Log.e(LOG_TAG, "Error starting printer state tracking", re);
    116         }
    117     }
    118 
    119     public final void stopPrinterStateTracking(@NonNull PrinterId printerId) {
    120         if (isDestroyed()) {
    121             Log.w(LOG_TAG, "Ignoring stop printer state tracking - session destroyed");
    122             return;
    123         }
    124         try {
    125             mPrintManager.stopPrinterStateTracking(printerId, mUserId);
    126         } catch (RemoteException re) {
    127             Log.e(LOG_TAG, "Error stopping printer state tracking", re);
    128         }
    129     }
    130 
    131     public final void validatePrinters(List<PrinterId> printerIds) {
    132         if (isDestroyed()) {
    133             Log.w(LOG_TAG, "Ignoring validate printers - session destroyed");
    134             return;
    135         }
    136         try {
    137             mPrintManager.validatePrinters(printerIds, mUserId);
    138         } catch (RemoteException re) {
    139             Log.e(LOG_TAG, "Error validating printers", re);
    140         }
    141     }
    142 
    143     public final void destroy() {
    144         if (isDestroyed()) {
    145             Log.w(LOG_TAG, "Ignoring destroy - session destroyed");
    146         }
    147         destroyNoCheck();
    148     }
    149 
    150     public final List<PrinterInfo> getPrinters() {
    151         if (isDestroyed()) {
    152             Log.w(LOG_TAG, "Ignoring get printers - session destroyed");
    153             return Collections.emptyList();
    154         }
    155         return new ArrayList<PrinterInfo>(mPrinters.values());
    156     }
    157 
    158     public final boolean isDestroyed() {
    159         throwIfNotCalledOnMainThread();
    160         return isDestroyedNoCheck();
    161     }
    162 
    163     public final boolean isPrinterDiscoveryStarted() {
    164         throwIfNotCalledOnMainThread();
    165         return mIsPrinterDiscoveryStarted;
    166     }
    167 
    168     public final void setOnPrintersChangeListener(OnPrintersChangeListener listener) {
    169         throwIfNotCalledOnMainThread();
    170         mListener = listener;
    171     }
    172 
    173     @Override
    174     protected final void finalize() throws Throwable {
    175         if (!isDestroyedNoCheck()) {
    176             Log.e(LOG_TAG, "Destroying leaked printer discovery session");
    177             destroyNoCheck();
    178         }
    179         super.finalize();
    180     }
    181 
    182     private boolean isDestroyedNoCheck() {
    183         return (mObserver == null);
    184     }
    185 
    186     private void destroyNoCheck() {
    187         stopPrinterDiscovery();
    188         try {
    189             mPrintManager.destroyPrinterDiscoverySession(mObserver, mUserId);
    190         } catch (RemoteException re) {
    191             Log.e(LOG_TAG, "Error destroying printer discovery session", re);
    192         } finally {
    193             mObserver = null;
    194             mPrinters.clear();
    195         }
    196     }
    197 
    198     private void handlePrintersAdded(List<PrinterInfo> addedPrinters) {
    199         if (isDestroyed()) {
    200             return;
    201         }
    202 
    203         // No old printers - do not bother keeping their position.
    204         if (mPrinters.isEmpty()) {
    205             final int printerCount = addedPrinters.size();
    206             for (int i = 0; i < printerCount; i++) {
    207                 PrinterInfo printer = addedPrinters.get(i);
    208                 mPrinters.put(printer.getId(), printer);
    209             }
    210             notifyOnPrintersChanged();
    211             return;
    212         }
    213 
    214         // Add the printers to a map.
    215         ArrayMap<PrinterId, PrinterInfo> addedPrintersMap =
    216                 new ArrayMap<PrinterId, PrinterInfo>();
    217         final int printerCount = addedPrinters.size();
    218         for (int i = 0; i < printerCount; i++) {
    219             PrinterInfo printer = addedPrinters.get(i);
    220             addedPrintersMap.put(printer.getId(), printer);
    221         }
    222 
    223         // Update printers we already have.
    224         for (PrinterId oldPrinterId : mPrinters.keySet()) {
    225             PrinterInfo updatedPrinter = addedPrintersMap.remove(oldPrinterId);
    226             if (updatedPrinter != null) {
    227                 mPrinters.put(oldPrinterId, updatedPrinter);
    228             }
    229         }
    230 
    231         // Add the new printers, i.e. what is left.
    232         mPrinters.putAll(addedPrintersMap);
    233 
    234         // Announce the change.
    235         notifyOnPrintersChanged();
    236     }
    237 
    238     private void handlePrintersRemoved(List<PrinterId> printerIds) {
    239         if (isDestroyed()) {
    240             return;
    241         }
    242         boolean printersChanged = false;
    243         final int removedPrinterIdCount = printerIds.size();
    244         for (int i = 0; i < removedPrinterIdCount; i++) {
    245             PrinterId removedPrinterId = printerIds.get(i);
    246             if (mPrinters.remove(removedPrinterId) != null) {
    247                 printersChanged = true;
    248             }
    249         }
    250         if (printersChanged) {
    251             notifyOnPrintersChanged();
    252         }
    253     }
    254 
    255     private void notifyOnPrintersChanged() {
    256         if (mListener != null) {
    257             mListener.onPrintersChanged();
    258         }
    259     }
    260 
    261     private static void throwIfNotCalledOnMainThread() {
    262         if (!Looper.getMainLooper().isCurrentThread()) {
    263             throw new IllegalAccessError("must be called from the main thread");
    264         }
    265     }
    266 
    267     private final class SessionHandler extends Handler {
    268 
    269         public SessionHandler(Looper looper) {
    270             super(looper, null, false);
    271         }
    272 
    273         @Override
    274         @SuppressWarnings("unchecked")
    275         public void handleMessage(Message message) {
    276             switch (message.what) {
    277                 case MSG_PRINTERS_ADDED: {
    278                     List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
    279                     handlePrintersAdded(printers);
    280                 } break;
    281 
    282                 case MSG_PRINTERS_REMOVED: {
    283                     List<PrinterId> printerIds = (List<PrinterId>) message.obj;
    284                     handlePrintersRemoved(printerIds);
    285                 } break;
    286             }
    287         }
    288     }
    289 
    290     public static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
    291 
    292         private final WeakReference<PrinterDiscoverySession> mWeakSession;
    293 
    294         public PrinterDiscoveryObserver(PrinterDiscoverySession session) {
    295             mWeakSession = new WeakReference<PrinterDiscoverySession>(session);
    296         }
    297 
    298         @Override
    299         @SuppressWarnings("rawtypes")
    300         public void onPrintersAdded(ParceledListSlice printers) {
    301             PrinterDiscoverySession session = mWeakSession.get();
    302             if (session != null) {
    303                 session.mHandler.obtainMessage(MSG_PRINTERS_ADDED,
    304                         printers.getList()).sendToTarget();
    305             }
    306         }
    307 
    308         @Override
    309         @SuppressWarnings("rawtypes")
    310         public void onPrintersRemoved(ParceledListSlice printerIds) {
    311             PrinterDiscoverySession session = mWeakSession.get();
    312             if (session != null) {
    313                 session.mHandler.obtainMessage(MSG_PRINTERS_REMOVED,
    314                         printerIds.getList()).sendToTarget();
    315             }
    316         }
    317     }
    318 }
    319