Home | History | Annotate | Download | only in bips
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  * Copyright (C) 2016 Mopria Alliance, Inc.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package com.android.bips;
     19 
     20 import android.content.BroadcastReceiver;
     21 import android.content.Context;
     22 import android.content.pm.PackageInfo;
     23 import android.content.pm.PackageManager;
     24 import android.net.nsd.NsdManager;
     25 import android.net.wifi.WifiManager;
     26 import android.os.Handler;
     27 import android.printservice.PrintJob;
     28 import android.printservice.PrintService;
     29 import android.printservice.PrinterDiscoverySession;
     30 import android.text.TextUtils;
     31 import android.util.Log;
     32 
     33 import com.android.bips.discovery.DelayedDiscovery;
     34 import com.android.bips.discovery.DiscoveredPrinter;
     35 import com.android.bips.discovery.Discovery;
     36 import com.android.bips.discovery.ManualDiscovery;
     37 import com.android.bips.discovery.MdnsDiscovery;
     38 import com.android.bips.discovery.MultiDiscovery;
     39 import com.android.bips.discovery.NsdResolveQueue;
     40 import com.android.bips.discovery.P2pDiscovery;
     41 import com.android.bips.ipp.Backend;
     42 import com.android.bips.ipp.CapabilitiesCache;
     43 import com.android.bips.p2p.P2pMonitor;
     44 import com.android.bips.p2p.P2pUtils;
     45 import com.android.bips.util.BroadcastMonitor;
     46 
     47 import java.lang.ref.WeakReference;
     48 
     49 public class BuiltInPrintService extends PrintService {
     50     private static final String TAG = BuiltInPrintService.class.getSimpleName();
     51     private static final boolean DEBUG = false;
     52     private static final int IPPS_PRINTER_DELAY = 150;
     53     private static final int P2P_DISCOVERY_DELAY = 1000;
     54 
     55     // Present because local activities can bind, but cannot access this object directly
     56     private static WeakReference<BuiltInPrintService> sInstance;
     57 
     58     private MultiDiscovery mAllDiscovery;
     59     private P2pDiscovery mP2pDiscovery;
     60     private Discovery mMdnsDiscovery;
     61     private ManualDiscovery mManualDiscovery;
     62     private CapabilitiesCache mCapabilitiesCache;
     63     private JobQueue mJobQueue;
     64     private Handler mMainHandler;
     65     private Backend mBackend;
     66     private WifiManager.WifiLock mWifiLock;
     67     private P2pMonitor mP2pMonitor;
     68     private NsdResolveQueue mNsdResolveQueue;
     69 
     70     /**
     71      * Return the current print service instance, if running
     72      */
     73     public static BuiltInPrintService getInstance() {
     74         return sInstance == null ? null : sInstance.get();
     75     }
     76 
     77     @Override
     78     public void onCreate() {
     79         if (DEBUG) {
     80             try {
     81                 PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
     82                 String version = pInfo.versionName;
     83                 Log.d(TAG, "onCreate() " + version);
     84             } catch (PackageManager.NameNotFoundException ignored) {
     85             }
     86         }
     87         super.onCreate();
     88 
     89         sInstance = new WeakReference<>(this);
     90         mBackend = new Backend(this);
     91         mCapabilitiesCache = new CapabilitiesCache(this, mBackend,
     92                 CapabilitiesCache.DEFAULT_MAX_CONCURRENT);
     93         mP2pMonitor = new P2pMonitor(this);
     94 
     95         NsdManager nsdManager = (NsdManager) getSystemService(Context.NSD_SERVICE);
     96         mNsdResolveQueue = new NsdResolveQueue(this, nsdManager);
     97 
     98         // Delay IPP results so that IPP is preferred
     99         Discovery ippDiscovery = new MdnsDiscovery(this, MdnsDiscovery.SCHEME_IPP);
    100         Discovery ippsDiscovery = new MdnsDiscovery(this, MdnsDiscovery.SCHEME_IPPS);
    101         mMdnsDiscovery = new MultiDiscovery(ippDiscovery, new DelayedDiscovery(ippsDiscovery, 0,
    102                 IPPS_PRINTER_DELAY));
    103         mP2pDiscovery = new P2pDiscovery(this);
    104         mManualDiscovery = new ManualDiscovery(this);
    105 
    106         // Delay P2P discovery so that all others are found first
    107         mAllDiscovery = new MultiDiscovery(mMdnsDiscovery, mManualDiscovery, new DelayedDiscovery(
    108                 mP2pDiscovery, P2P_DISCOVERY_DELAY, 0));
    109 
    110         mJobQueue = new JobQueue();
    111         mMainHandler = new Handler(getMainLooper());
    112         WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    113         mWifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG);
    114     }
    115 
    116     @Override
    117     public void onDestroy() {
    118         if (DEBUG) Log.d(TAG, "onDestroy()");
    119         mCapabilitiesCache.close();
    120         mP2pMonitor.stopAll();
    121         mBackend.close();
    122         unlockWifi();
    123         sInstance = null;
    124         mMainHandler.removeCallbacksAndMessages(null);
    125         super.onDestroy();
    126     }
    127 
    128     @Override
    129     protected PrinterDiscoverySession onCreatePrinterDiscoverySession() {
    130         if (DEBUG) Log.d(TAG, "onCreatePrinterDiscoverySession");
    131         return new LocalDiscoverySession(this);
    132     }
    133 
    134     @Override
    135     protected void onPrintJobQueued(PrintJob printJob) {
    136         if (DEBUG) Log.d(TAG, "onPrintJobQueued");
    137         mJobQueue.print(new LocalPrintJob(this, mBackend, printJob));
    138     }
    139 
    140     @Override
    141     protected void onRequestCancelPrintJob(PrintJob printJob) {
    142         if (DEBUG) Log.d(TAG, "onRequestCancelPrintJob");
    143         mJobQueue.cancel(printJob.getId());
    144     }
    145 
    146     /**
    147      * Return the global discovery object
    148      */
    149     public Discovery getDiscovery() {
    150         return mAllDiscovery;
    151     }
    152 
    153     /**
    154      * Return the global object for MDNS discoveries
    155      */
    156     public Discovery getMdnsDiscovery() {
    157         return mMdnsDiscovery;
    158     }
    159 
    160     /**
    161      * Return the global object for manual discoveries
    162      */
    163     public ManualDiscovery getManualDiscovery() {
    164         return mManualDiscovery;
    165     }
    166 
    167     /**
    168      * Return the global object for Wi-Fi Direct printer discoveries
    169      */
    170     public P2pDiscovery getP2pDiscovery() {
    171         return mP2pDiscovery;
    172     }
    173 
    174     /**
    175      * Return the global object for general Wi-Fi Direct management
    176      */
    177     public P2pMonitor getP2pMonitor() {
    178         return mP2pMonitor;
    179     }
    180 
    181     /**
    182      * Return the global {@link NsdResolveQueue}
    183      */
    184     public NsdResolveQueue getNsdResolveQueue() {
    185         return mNsdResolveQueue;
    186     }
    187 
    188     /**
    189      * Listen for a set of broadcast messages until stopped
    190      */
    191     public BroadcastMonitor receiveBroadcasts(BroadcastReceiver receiver, String... actions) {
    192         return new BroadcastMonitor(this, receiver, actions);
    193     }
    194 
    195     /**
    196      * Return the global Printer Capabilities cache
    197      */
    198     public CapabilitiesCache getCapabilitiesCache() {
    199         return mCapabilitiesCache;
    200     }
    201 
    202     /**
    203      * Return the main handler for posting {@link Runnable} objects to the main UI
    204      */
    205     public Handler getMainHandler() {
    206         return mMainHandler;
    207     }
    208 
    209     /** Run something on the main thread, returning an object that can cancel the request */
    210     public DelayedAction delay(int delay, Runnable toRun) {
    211         mMainHandler.postDelayed(toRun, delay);
    212         return () -> mMainHandler.removeCallbacks(toRun);
    213     }
    214 
    215     /**
    216      * Return a friendly description string including host and (if present) location
    217      */
    218     public String getDescription(DiscoveredPrinter printer) {
    219         if (P2pUtils.isP2p(printer) || P2pUtils.isOnConnectedInterface(this, printer)) {
    220             return getString(R.string.wifi_direct);
    221         }
    222 
    223         String host = printer.getHost();
    224         if (!TextUtils.isEmpty(printer.location)) {
    225             return getString(R.string.printer_description, host, printer.location);
    226         } else {
    227             return host;
    228         }
    229     }
    230 
    231     /** Prevent Wi-Fi from going to sleep until {@link #unlockWifi} is called */
    232     public void lockWifi() {
    233         if (!mWifiLock.isHeld()) {
    234             mWifiLock.acquire();
    235         }
    236     }
    237 
    238     /** Allow Wi-Fi to be disabled during sleep modes. */
    239     public void unlockWifi() {
    240         if (mWifiLock.isHeld()) {
    241             mWifiLock.release();
    242         }
    243     }
    244 }
    245