• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 com.android.bips.ui;
18 
19 import android.app.ActionBar;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.ServiceConnection;
24 import android.os.Bundle;
25 import android.os.IBinder;
26 import android.print.PrintJobInfo;
27 import android.print.PrinterId;
28 import android.printservice.PrintService;
29 import android.util.Log;
30 import android.view.MenuItem;
31 import android.view.View;
32 import android.widget.LinearLayout;
33 import android.widget.Toast;
34 
35 import androidx.fragment.app.FragmentActivity;
36 import androidx.fragment.app.FragmentManager;
37 import androidx.lifecycle.ViewModelProvider;
38 
39 import com.android.bips.BuiltInPrintService;
40 import com.android.bips.R;
41 import com.android.bips.discovery.ConnectionListener;
42 import com.android.bips.discovery.DiscoveredPrinter;
43 import com.android.bips.discovery.Discovery;
44 import com.android.bips.flags.Flags;
45 import com.android.bips.p2p.P2pPrinterConnection;
46 import com.android.bips.p2p.P2pUtils;
47 
48 import java.net.InetAddress;
49 import java.net.UnknownHostException;
50 import java.util.concurrent.ExecutorService;
51 import java.util.concurrent.Executors;
52 
53 /**
54  * Launched by system in response to a "More Options" request while tracking a printer.
55  */
56 public class MoreOptionsActivity extends FragmentActivity implements ServiceConnection,
57         Discovery.Listener {
58     private static final String TAG = MoreOptionsActivity.class.getSimpleName();
59 
60     private static final boolean DEBUG = false;
61 
62     private BuiltInPrintService mPrintService;
63     PrinterId mPrinterId;
64     DiscoveredPrinter mPrinter;
65     InetAddress mPrinterAddress;
66     public static final String EXTRA_PRINTER_ID = "EXTRA_PRINTER_ID";
67     private static final String TAG_RECOMMENDATION_FRAGMENT = "recommendation_fragment";
68     private static final String TAG_PRINTER_INFORMATION_FRAGMENT = "printer_information_fragment";
69     private PrinterInformationViewModel mPrinterInformationViewModel;
70     private LinearLayout mLlRecommendedServices;
71     private LinearLayout mLlRecommendedServicesSummary;
72     private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
73     private P2pPrinterConnection mP2pPrinterConnection;
74 
75     @Override
onCreate(Bundle savedInstanceState)76     protected void onCreate(Bundle savedInstanceState) {
77         super.onCreate(savedInstanceState);
78         if (getIntent().hasExtra(PrintService.EXTRA_PRINT_JOB_INFO)) {
79             PrintJobInfo jobInfo =
80                     getIntent().getParcelableExtra(PrintService.EXTRA_PRINT_JOB_INFO);
81             mPrinterId = jobInfo.getPrinterId();
82         } else if (getIntent().hasExtra(EXTRA_PRINTER_ID)) {
83             mPrinterId = getIntent().getParcelableExtra(EXTRA_PRINTER_ID);
84         } else {
85             if (DEBUG) Log.i(TAG, "No job info or printer info to show. Exiting.");
86             finish();
87             return;
88         }
89         ActionBar actionBar = getActionBar();
90         if (actionBar != null) {
91             actionBar.setDisplayHomeAsUpEnabled(true);
92         }
93         if ((Flags.printerInfoDetails())) {
94             setContentView(R.layout.combined_info_recs);
95             mPrinterInformationViewModel =
96                     new ViewModelProvider(this).get(PrinterInformationViewModel.class);
97             getSupportFragmentManager().popBackStack(null,
98                     FragmentManager.POP_BACK_STACK_INCLUSIVE);
99             mLlRecommendedServicesSummary = findViewById(R.id.ll_recommended_services_summary);
100             mLlRecommendedServices = findViewById(R.id.ll_recommended_services);
101             mLlRecommendedServices.setOnClickListener(view -> {
102                 if (getSupportFragmentManager().findFragmentByTag(TAG_RECOMMENDATION_FRAGMENT)
103                         == null) {
104                     MoreOptionsFragment fragment = new MoreOptionsFragment();
105                     getSupportFragmentManager().beginTransaction()
106                             .replace(R.id.fragment_container, fragment, TAG_RECOMMENDATION_FRAGMENT)
107                             .setReorderingAllowed(true)
108                             .addToBackStack(null)
109                             .commit();
110                     mLlRecommendedServices.setVisibility(View.GONE);
111                     mLlRecommendedServicesSummary.setVisibility(View.GONE);
112                 }
113             });
114             getSupportFragmentManager().addOnBackStackChangedListener(
115                     () -> {
116                         if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
117                             mLlRecommendedServices.setVisibility(View.VISIBLE);
118                             mLlRecommendedServicesSummary.setVisibility(View.VISIBLE);
119                             if (mPrinter != null) {
120                                 setTitle(mPrinter.name);
121                             }
122                         }
123                     });
124             setTitle(R.string.information);
125         } else {
126             getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
127         }
128 
129         ViewUtil.setWindowInsetsListener(getWindow().getDecorView(), this);
130     }
131 
132     @Override
onOptionsItemSelected(MenuItem item)133     public boolean onOptionsItemSelected(MenuItem item) {
134         switch (item.getItemId()) {
135             case android.R.id.home:
136                 finish();
137                 return true;
138         }
139         return super.onOptionsItemSelected(item);
140     }
141 
142     @Override
onStart()143     protected void onStart() {
144         super.onStart();
145         bindService(new Intent(this, BuiltInPrintService.class), this,
146                 Context.BIND_AUTO_CREATE);
147     }
148 
149     @Override
onStop()150     protected void onStop() {
151         super.onStop();
152 
153         if (mP2pPrinterConnection != null) {
154             mP2pPrinterConnection.close();
155             mP2pPrinterConnection = null;
156         }
157 
158         if (mPrintService != null) {
159             if ((Flags.printerInfoDetails())) {
160                 mPrinterInformationViewModel.stopPrinterStatusMonitor(mPrintService);
161             }
162             mPrintService.getDiscovery().stop(this);
163         }
164         unbindService(this);
165     }
166 
167     @Override
onDestroy()168     protected void onDestroy() {
169         super.onDestroy();
170         mExecutorService.shutdownNow();
171     }
172 
173     @Override
onServiceConnected(ComponentName name, IBinder service)174     public void onServiceConnected(ComponentName name, IBinder service) {
175         mPrintService = BuiltInPrintService.getInstance();
176         mPrintService.getDiscovery().start(this);
177     }
178 
179     @Override
onServiceDisconnected(ComponentName name)180     public void onServiceDisconnected(ComponentName name) {
181         mPrintService = null;
182     }
183 
184     @Override
onPrinterFound(DiscoveredPrinter printer)185     public void onPrinterFound(DiscoveredPrinter printer) {
186         // Return when P2P connection is in progress
187         if (mP2pPrinterConnection != null) {
188             return;
189         }
190 
191         if (printer.getUri().toString().equals(mPrinterId.getLocalId())) {
192             // We discovered a printer matching the job's PrinterId, so show recommendations
193             if (P2pUtils.isP2p(printer)) {
194                 // Printer is not connected on p2p interface
195                 connectP2P(printer);
196             } else {
197                 loadPrinterInfoFragment(printer);
198             }
199         }
200     }
201 
connectP2P(DiscoveredPrinter printer)202     private void connectP2P(DiscoveredPrinter printer) {
203         Toast.makeText(mPrintService, getString(R.string.connecting_to, printer.name),
204                 Toast.LENGTH_LONG).show();
205 
206         mP2pPrinterConnection = new P2pPrinterConnection(mPrintService, printer,
207                 new ConnectionListener() {
208                     @Override
209                     public void onConnectionComplete(DiscoveredPrinter printer) {
210                         if (DEBUG) Log.d(TAG, "onConnectionComplete(), printer = " + printer);
211                         if (printer != null && printer.paths.size() > 1) {
212                             loadPrinterInfoFragment(
213                                     new DiscoveredPrinter(printer.uuid, printer.name,
214                                             printer.paths.get(1), printer.location));
215                         } else {
216                             Toast.makeText(mPrintService, R.string.failed_printer_connection,
217                                     Toast.LENGTH_LONG).show();
218                             if (mP2pPrinterConnection != null) {
219                                 mP2pPrinterConnection.close();
220                                 mP2pPrinterConnection = null;
221                             }
222                         }
223                     }
224 
225                     @Override
226                     public void onConnectionDelayed(boolean delayed) {
227                         if (delayed) {
228                             Toast.makeText(mPrintService, R.string.connect_hint_text,
229                                     Toast.LENGTH_LONG).show();
230                         }
231                     }
232                 });
233     }
234 
loadPrinterInfoFragment(DiscoveredPrinter printer)235     private void loadPrinterInfoFragment(DiscoveredPrinter printer) {
236         mPrinter = printer;
237         setTitle(mPrinter.name);
238         if ((Flags.printerInfoDetails())) {
239             if (printer.path != null) {
240                 mPrinterInformationViewModel.getPrinterStatus(printer.path, mPrintService);
241             } else {
242                 mPrinterInformationViewModel.setPrinterUnavailableLiveData(true);
243             }
244         }
245         // Network operation in non UI thread
246         mExecutorService.execute(() -> {
247             try {
248                 mPrinterAddress = InetAddress.getByName(mPrinter.path.getHost());
249                 // No need for continued discovery after we find the printer.
250                 mPrintService.getDiscovery().stop(this);
251                 if (!mExecutorService.isShutdown() && mPrintService != null) {
252                     mPrintService.getMainHandler().post(() -> {
253                         if ((Flags.printerInfoDetails())) {
254                             if (getSupportFragmentManager().findFragmentByTag(
255                                     TAG_PRINTER_INFORMATION_FRAGMENT) == null) {
256                                 PrinterInformationFragment informationFragment =
257                                         new PrinterInformationFragment();
258                                 getSupportFragmentManager().beginTransaction()
259                                         .replace(R.id.fragment_container, informationFragment,
260                                                 TAG_PRINTER_INFORMATION_FRAGMENT)
261                                         .commit();
262                             }
263                             mPrintService.getCapabilitiesCache().request(mPrinter, true,
264                                     capabilities -> {
265                                         if (capabilities != null) {
266                                             mPrinterInformationViewModel.setPrinterCapsLiveData(
267                                                     capabilities);
268                                         } else {
269                                             mPrinterInformationViewModel.setPrinterUnavailableLiveData(
270                                                     true);
271                                             Toast.makeText(mPrintService,
272                                                     R.string.failed_printer_connection,
273                                                     Toast.LENGTH_LONG).show();
274                                         }
275                                     });
276                         } else {
277                             if (getFragmentManager().findFragmentByTag(TAG_RECOMMENDATION_FRAGMENT)
278                                     == null) {
279                                 MoreOptionsFragment fragment = new MoreOptionsFragment();
280                                 getSupportFragmentManager().beginTransaction()
281                                         .replace(android.R.id.content, fragment,
282                                                 TAG_RECOMMENDATION_FRAGMENT)
283                                         .commit();
284                             }
285                         }
286                     });
287                 }
288             } catch (UnknownHostException ignored) {
289             }
290         });
291     }
292 
293     @Override
onPrinterLost(DiscoveredPrinter printer)294     public void onPrinterLost(DiscoveredPrinter printer) {
295         // Ignore
296     }
297 }
298