434d4a2e33e9e85d297bad237eb67cb4e98a53dc
[platform/framework/web/crosswalk.git] / src / chrome / browser / devtools / device / usb / android_usb_browsertest.cc
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <algorithm>
6
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/devtools/device/devtools_android_bridge.h"
9 #include "chrome/browser/devtools/device/usb/android_usb_device.h"
10 #include "chrome/browser/devtools/device/usb/usb_device_provider.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/test/base/in_process_browser_test.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/test/test_utils.h"
15 #include "device/usb/usb_descriptors.h"
16 #include "device/usb/usb_device.h"
17 #include "device/usb/usb_device_handle.h"
18 #include "device/usb/usb_service.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 using content::BrowserThread;
22 using device::UsbConfigDescriptor;
23 using device::UsbDevice;
24 using device::UsbDeviceHandle;
25 using device::UsbEndpointDescriptor;
26 using device::UsbEndpointDirection;
27 using device::UsbInterfaceDescriptor;
28 using device::UsbService;
29 using device::UsbSynchronizationType;
30 using device::UsbTransferCallback;
31 using device::UsbTransferType;
32 using device::UsbUsageType;
33
34 namespace {
35
36 struct AndroidTraits {
37   static const int kClass = 0xff;
38   static const int kSubclass = 0x42;
39   static const int kProtocol = 0x1;
40 };
41
42 struct NonAndroidTraits {
43   static const int kClass = 0xf0;
44   static const int kSubclass = 0x42;
45   static const int kProtocol = 0x2;
46 };
47
48 const uint32 kMaxPayload = 4096;
49 const uint32 kVersion = 0x01000000;
50
51 const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
52 const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
53 const char kDumpsysCommand[] = "shell:dumpsys window policy";
54 const char kListProcessesCommand[] = "shell:ps";
55 const char kInstalledChromePackagesCommand[] = "shell:pm list packages";
56 const char kDeviceManufacturer[] = "Test Manufacturer";
57 const char kDeviceModel[] = "Nexus 5";
58 const char kDeviceSerial[] = "Sample serial";
59
60 const char kSampleOpenedUnixSockets[] =
61     "Num       RefCount Protocol Flags    Type St Inode Path\n"
62     "00000000: 00000004 00000000"
63     " 00000000 0002 01  3328 /dev/socket/wpa_wlan0\n"
64     "00000000: 00000002 00000000"
65     " 00010000 0001 01  5394 /dev/socket/vold\n";
66
67 const char kSampleListProcesses[] =
68     "USER   PID  PPID VSIZE  RSS    WCHAN    PC         NAME\n"
69     "root   1    0    688    508    ffffffff 00000000 S /init\r\n"
70     "u0_a75 2425 123  933736 193024 ffffffff 00000000 S com.sample.feed\r\n"
71     "nfc    741  123  706448 26316  ffffffff 00000000 S com.android.nfc\r\n"
72     "u0_a76 1001 124  111111 222222 ffffffff 00000000 S com.android.chrome\r\n"
73     "u0_a78 1003 126  111111 222222 ffffffff 00000000 S com.noprocess.app\r\n";
74
75 const char kSampleListPackages[] =
76     "package:com.sample.feed\r\n"
77     "package:com.android.nfc\r\n"
78     "package:com.android.chrome\r\n"
79     "package:com.chrome.beta\r\n"
80     "package:com.google.android.apps.chrome\r\n";
81
82 const char kSampleDumpsys[] =
83     "WINDOW MANAGER POLICY STATE (dumpsys window policy)\r\n"
84     "    mSafeMode=false mSystemReady=true mSystemBooted=true\r\n"
85     "    mStable=(0,50)-(720,1184)\r\n"  // Only mStable parameter is parsed
86     "    mForceStatusBar=false mForceStatusBarFromKeyguard=false\r\n";
87
88 const char* GetMockShellResponse(std::string command) {
89   if (command == kDeviceModelCommand) {
90     return kDeviceModel;
91   } else if (command == kOpenedUnixSocketsCommand) {
92     return kSampleOpenedUnixSockets;
93   } else if (command == kDumpsysCommand) {
94     return kSampleDumpsys;
95   } else if (command == kListProcessesCommand) {
96     return kSampleListProcesses;
97   } else if (command == kInstalledChromePackagesCommand) {
98     return kSampleListPackages;
99   }
100
101   DCHECK(false) << "Should not be reached";
102
103   return "";
104 }
105
106 template <class T>
107 class MockUsbDevice;
108
109 template <class T>
110 class MockUsbDeviceHandle : public UsbDeviceHandle {
111  public:
112   explicit MockUsbDeviceHandle(MockUsbDevice<T>* device)
113       : device_(device),
114         remaining_body_length_(0),
115         next_local_socket_(0) {}
116
117   virtual scoped_refptr<UsbDevice> GetDevice() const override {
118     return device_;
119   }
120
121   virtual void Close() override { device_ = NULL; }
122
123   bool ClaimInterface(int interface_number) {
124     if (device_->claimed_interfaces_.find(interface_number) !=
125         device_->claimed_interfaces_.end())
126       return false;
127
128     device_->claimed_interfaces_.insert(interface_number);
129     return true;
130   }
131
132   bool ReleaseInterface(int interface_number) {
133     if (device_->claimed_interfaces_.find(interface_number) ==
134         device_->claimed_interfaces_.end())
135       return false;
136
137     device_->claimed_interfaces_.erase(interface_number);
138     return true;
139   }
140
141   virtual bool SetInterfaceAlternateSetting(int interface_number,
142                                             int alternate_setting) override {
143     return true;
144   }
145
146   virtual bool ResetDevice() override { return true; }
147   virtual bool GetStringDescriptor(uint8_t string_id, base::string16* content) {
148     return false;
149   }
150
151   // Async IO. Can be called on any thread.
152   virtual void ControlTransfer(UsbEndpointDirection direction,
153                                TransferRequestType request_type,
154                                TransferRecipient recipient,
155                                uint8 request,
156                                uint16 value,
157                                uint16 index,
158                                net::IOBuffer* buffer,
159                                size_t length,
160                                unsigned int timeout,
161                                const UsbTransferCallback& callback) override {}
162
163   virtual void BulkTransfer(UsbEndpointDirection direction,
164                             uint8 endpoint,
165                             net::IOBuffer* buffer,
166                             size_t length,
167                             unsigned int timeout,
168                             const UsbTransferCallback& callback) override {
169     if (direction == device::USB_DIRECTION_OUTBOUND) {
170       if (remaining_body_length_ == 0) {
171         std::vector<uint32> header(6);
172         memcpy(&header[0], buffer->data(), length);
173         current_message_ = new AdbMessage(header[0], header[1], header[2], "");
174         remaining_body_length_ = header[3];
175         uint32 magic = header[5];
176         if ((current_message_->command ^ 0xffffffff) != magic) {
177           DCHECK(false) << "Header checksum error";
178           return;
179         }
180       } else {
181         DCHECK(current_message_.get());
182         current_message_->body += std::string(buffer->data(), length);
183         remaining_body_length_ -= length;
184       }
185
186       if (remaining_body_length_ == 0) {
187         ProcessIncoming();
188       }
189
190       base::MessageLoop::current()->PostTask(
191           FROM_HERE,
192           base::Bind(callback,
193                      device::USB_TRANSFER_COMPLETED,
194                      scoped_refptr<net::IOBuffer>(),
195                      0));
196
197     } else if (direction == device::USB_DIRECTION_INBOUND) {
198       queries_.push(Query(callback, make_scoped_refptr(buffer), length));
199       ProcessQueries();
200     }
201   }
202
203   template <class D>
204   void append(D data) {
205     std::copy(reinterpret_cast<char*>(&data),
206               (reinterpret_cast<char*>(&data)) + sizeof(D),
207               std::back_inserter(output_buffer_));
208   }
209
210   // Copied from AndroidUsbDevice::Checksum
211   uint32 Checksum(const std::string& data) {
212     unsigned char* x = (unsigned char*)data.data();
213     int count = data.length();
214     uint32 sum = 0;
215     while (count-- > 0)
216       sum += *x++;
217     return sum;
218   }
219
220   void ProcessIncoming() {
221     DCHECK(current_message_.get());
222     switch (current_message_->command) {
223       case AdbMessage::kCommandCNXN:
224         WriteResponse(new AdbMessage(AdbMessage::kCommandCNXN,
225                                      kVersion,
226                                      kMaxPayload,
227                                      "device::ro.product.name=SampleProduct;ro."
228                                      "product.model=SampleModel;ro.product."
229                                      "device=SampleDevice;"));
230         break;
231       case AdbMessage::kCommandOPEN:
232         DCHECK(current_message_->arg1 == 0);
233         DCHECK(current_message_->arg0 != 0);
234         if (current_message_->body.find("shell:") != std::string::npos) {
235           WriteResponse(new AdbMessage(AdbMessage::kCommandOKAY,
236                                        ++next_local_socket_,
237                                        current_message_->arg0,
238                                        ""));
239           WriteResponse(
240               new AdbMessage(AdbMessage::kCommandWRTE,
241                              next_local_socket_,
242                              current_message_->arg0,
243                              GetMockShellResponse(current_message_->body.substr(
244                                  0, current_message_->body.size() - 1))));
245           WriteResponse(new AdbMessage(
246               AdbMessage::kCommandCLSE, 0, current_message_->arg0, ""));
247         }
248       default:
249         return;
250     }
251     ProcessQueries();
252   }
253
254   void WriteResponse(scoped_refptr<AdbMessage> response) {
255     append(response->command);
256     append(response->arg0);
257     append(response->arg1);
258     bool add_zero = response->body.length() &&
259                     (response->command != AdbMessage::kCommandWRTE);
260     append(static_cast<uint32>(response->body.length() + (add_zero ? 1 : 0)));
261     append(Checksum(response->body));
262     append(response->command ^ 0xffffffff);
263     std::copy(response->body.begin(),
264               response->body.end(),
265               std::back_inserter(output_buffer_));
266     if (add_zero) {
267       output_buffer_.push_back(0);
268     }
269     ProcessQueries();
270   }
271
272   void ProcessQueries() {
273     if (!queries_.size())
274       return;
275     Query query = queries_.front();
276
277     if (query.size > output_buffer_.size())
278       return;
279
280     queries_.pop();
281     std::copy(output_buffer_.begin(),
282               output_buffer_.begin() + query.size,
283               query.buffer->data());
284     output_buffer_.erase(output_buffer_.begin(),
285                          output_buffer_.begin() + query.size);
286     base::MessageLoop::current()->PostTask(
287         FROM_HERE,
288         base::Bind(query.callback,
289                    device::USB_TRANSFER_COMPLETED,
290                    query.buffer,
291                    query.size));
292   }
293
294   virtual void InterruptTransfer(UsbEndpointDirection direction,
295                                  uint8 endpoint,
296                                  net::IOBuffer* buffer,
297                                  size_t length,
298                                  unsigned int timeout,
299                                  const UsbTransferCallback& callback) override {
300   }
301
302   virtual void IsochronousTransfer(
303       UsbEndpointDirection direction,
304       uint8 endpoint,
305       net::IOBuffer* buffer,
306       size_t length,
307       unsigned int packets,
308       unsigned int packet_length,
309       unsigned int timeout,
310       const UsbTransferCallback& callback) override {}
311
312  protected:
313   virtual ~MockUsbDeviceHandle() {}
314
315   struct Query {
316     UsbTransferCallback callback;
317     scoped_refptr<net::IOBuffer> buffer;
318     size_t size;
319
320     Query(UsbTransferCallback callback,
321           scoped_refptr<net::IOBuffer> buffer,
322           int size)
323         : callback(callback), buffer(buffer), size(size) {};
324   };
325
326   scoped_refptr<MockUsbDevice<T> > device_;
327   uint32 remaining_body_length_;
328   scoped_refptr<AdbMessage> current_message_;
329   std::vector<char> output_buffer_;
330   std::queue<Query> queries_;
331   int next_local_socket_;
332 };
333
334 template <class T>
335 class MockUsbDevice : public UsbDevice {
336  public:
337   MockUsbDevice() : UsbDevice(0, 0, 0) {
338     UsbEndpointDescriptor bulk_in;
339     bulk_in.address = 0x81;
340     bulk_in.direction = device::USB_DIRECTION_INBOUND;
341     bulk_in.maximum_packet_size = 512;
342     bulk_in.transfer_type = device::USB_TRANSFER_BULK;
343
344     UsbEndpointDescriptor bulk_out;
345     bulk_out.address = 0x01;
346     bulk_out.direction = device::USB_DIRECTION_OUTBOUND;
347     bulk_out.maximum_packet_size = 512;
348     bulk_out.transfer_type = device::USB_TRANSFER_BULK;
349
350     UsbInterfaceDescriptor interface_desc;
351     interface_desc.interface_number = 0;
352     interface_desc.alternate_setting = 0;
353     interface_desc.interface_class = T::kClass;
354     interface_desc.interface_subclass = T::kSubclass;
355     interface_desc.interface_protocol = T::kProtocol;
356     interface_desc.endpoints.push_back(bulk_in);
357     interface_desc.endpoints.push_back(bulk_out);
358
359     config_desc_.interfaces.push_back(interface_desc);
360   }
361
362   virtual scoped_refptr<UsbDeviceHandle> Open() override {
363     return new MockUsbDeviceHandle<T>(this);
364   }
365
366   virtual const UsbConfigDescriptor& GetConfiguration() override {
367     return config_desc_;
368   }
369
370   virtual bool GetManufacturer(base::string16* manufacturer) override {
371     *manufacturer = base::UTF8ToUTF16(kDeviceManufacturer);
372     return true;
373   }
374
375   virtual bool GetProduct(base::string16* product) override {
376     *product = base::UTF8ToUTF16(kDeviceModel);
377     return true;
378   }
379
380   virtual bool GetSerialNumber(base::string16* serial) override {
381     *serial = base::UTF8ToUTF16(kDeviceSerial);
382     return true;
383   }
384
385   virtual bool Close(scoped_refptr<UsbDeviceHandle> handle) override {
386     return true;
387   }
388
389 #if defined(OS_CHROMEOS)
390   // On ChromeOS, if an interface of a claimed device is not claimed, the
391   // permission broker can change the owner of the device so that the unclaimed
392   // interfaces can be used. If this argument is missing, permission broker will
393   // not be used and this method fails if the device is claimed.
394   virtual void RequestUsbAccess(
395       int interface_id,
396       const base::Callback<void(bool success)>& callback) override {
397     callback.Run(true);
398   }
399 #endif  // OS_CHROMEOS
400
401   std::set<int> claimed_interfaces_;
402
403  protected:
404   virtual ~MockUsbDevice() {}
405
406  private:
407   UsbConfigDescriptor config_desc_;
408 };
409
410 class MockUsbService : public UsbService {
411  public:
412   MockUsbService() {
413     devices_.push_back(new MockUsbDevice<AndroidTraits>());
414   }
415
416   ~MockUsbService() override {}
417
418   scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) override {
419     NOTIMPLEMENTED();
420     return NULL;
421   }
422
423   void GetDevices(std::vector<scoped_refptr<UsbDevice>>* devices) override {
424     STLClearObject(devices);
425     std::copy(devices_.begin(), devices_.end(), back_inserter(*devices));
426   }
427
428   std::vector<scoped_refptr<UsbDevice> > devices_;
429 };
430
431 class MockUsbServiceForCheckingTraits : public UsbService {
432  public:
433   MockUsbServiceForCheckingTraits() : step_(0) {}
434
435   ~MockUsbServiceForCheckingTraits() override {}
436
437   scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) override {
438     NOTIMPLEMENTED();
439     return NULL;
440   }
441
442   void GetDevices(std::vector<scoped_refptr<UsbDevice>>* devices) override {
443     STLClearObject(devices);
444     // This switch should be kept in sync with
445     // AndroidUsbBrowserTest::DeviceCountChanged.
446     switch (step_) {
447       case 0:
448         // No devices.
449         break;
450       case 1:
451         // Android device.
452         devices->push_back(new MockUsbDevice<AndroidTraits>());
453         break;
454       case 2:
455         // Android and non-android device.
456         devices->push_back(new MockUsbDevice<AndroidTraits>());
457         devices->push_back(new MockUsbDevice<NonAndroidTraits>());
458         break;
459       case 3:
460         // Non-android device.
461         devices->push_back(new MockUsbDevice<NonAndroidTraits>());
462         break;
463     }
464     step_++;
465   }
466
467  private:
468   int step_;
469 };
470
471 class DevToolsAndroidBridgeWarmUp
472     : public DevToolsAndroidBridge::DeviceCountListener {
473  public:
474   DevToolsAndroidBridgeWarmUp(base::Closure closure,
475                               scoped_refptr<DevToolsAndroidBridge> adb_bridge)
476       : closure_(closure), adb_bridge_(adb_bridge) {}
477
478   void DeviceCountChanged(int count) override {
479     adb_bridge_->RemoveDeviceCountListener(this);
480     closure_.Run();
481   }
482
483   base::Closure closure_;
484   scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
485 };
486
487 class AndroidUsbDiscoveryTest : public InProcessBrowserTest {
488  protected:
489   AndroidUsbDiscoveryTest()
490       : scheduler_invoked_(0) {
491   }
492   void SetUpOnMainThread() override {
493     scoped_refptr<content::MessageLoopRunner> runner =
494         new content::MessageLoopRunner;
495
496     BrowserThread::PostTaskAndReply(
497         BrowserThread::FILE,
498         FROM_HERE,
499         base::Bind(&AndroidUsbDiscoveryTest::SetUpService, this),
500         runner->QuitClosure());
501     runner->Run();
502
503     adb_bridge_ =
504         DevToolsAndroidBridge::Factory::GetForProfile(browser()->profile());
505     DCHECK(adb_bridge_.get());
506     adb_bridge_->set_task_scheduler_for_test(base::Bind(
507         &AndroidUsbDiscoveryTest::ScheduleDeviceCountRequest, this));
508
509     scoped_refptr<UsbDeviceProvider> provider =
510         new UsbDeviceProvider(browser()->profile());
511
512     AndroidDeviceManager::DeviceProviders providers;
513     providers.push_back(provider);
514     adb_bridge_->set_device_providers_for_test(providers);
515     runner_ = new content::MessageLoopRunner;
516   }
517
518   void ScheduleDeviceCountRequest(const base::Closure& request) {
519     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
520     scheduler_invoked_++;
521     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, request);
522   }
523
524   virtual void SetUpService() {
525     UsbService::SetInstanceForTest(new MockUsbService());
526   }
527
528   void TearDownOnMainThread() override {
529     scoped_refptr<content::MessageLoopRunner> runner =
530         new content::MessageLoopRunner;
531     UsbService* service = NULL;
532     BrowserThread::PostTaskAndReply(
533         BrowserThread::FILE,
534         FROM_HERE,
535         base::Bind(&UsbService::SetInstanceForTest, service),
536         runner->QuitClosure());
537     runner->Run();
538   }
539
540   scoped_refptr<content::MessageLoopRunner> runner_;
541   scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
542   int scheduler_invoked_;
543 };
544
545 class AndroidUsbCountTest : public AndroidUsbDiscoveryTest {
546  protected:
547   void SetUpOnMainThread() override {
548     AndroidUsbDiscoveryTest::SetUpOnMainThread();
549     DevToolsAndroidBridgeWarmUp warmup(runner_->QuitClosure(), adb_bridge_);
550     adb_bridge_->AddDeviceCountListener(&warmup);
551     runner_->Run();
552     runner_ = new content::MessageLoopRunner;
553   }
554 };
555
556 class AndroidUsbTraitsTest : public AndroidUsbDiscoveryTest {
557  protected:
558   void SetUpService() override {
559     UsbService::SetInstanceForTest(new MockUsbServiceForCheckingTraits());
560   }
561 };
562
563 class MockListListener : public DevToolsAndroidBridge::DeviceListListener {
564  public:
565   MockListListener(scoped_refptr<DevToolsAndroidBridge> adb_bridge,
566                    const base::Closure& callback)
567       : adb_bridge_(adb_bridge),
568         callback_(callback) {
569   }
570
571   void DeviceListChanged(
572       const DevToolsAndroidBridge::RemoteDevices& devices) override {
573     if (devices.size() > 0) {
574       if (devices[0]->is_connected()) {
575         ASSERT_EQ(kDeviceModel, devices[0]->model());
576         ASSERT_EQ(kDeviceSerial, devices[0]->serial());
577         adb_bridge_->RemoveDeviceListListener(this);
578         callback_.Run();
579       }
580     }
581   }
582
583   scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
584   base::Closure callback_;
585 };
586
587 class MockCountListener : public DevToolsAndroidBridge::DeviceCountListener {
588  public:
589   explicit MockCountListener(scoped_refptr<DevToolsAndroidBridge> adb_bridge)
590       : adb_bridge_(adb_bridge),
591         reposts_left_(10),
592         invoked_(0) {
593   }
594
595   void DeviceCountChanged(int count) override {
596     ++invoked_;
597     adb_bridge_->RemoveDeviceCountListener(this);
598     Shutdown();
599   }
600
601   void Shutdown() {
602     ShutdownOnUIThread();
603   };
604
605   void ShutdownOnUIThread() {
606     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
607     if (reposts_left_-- == 0) {
608       base::MessageLoop::current()->Quit();
609     } else {
610       BrowserThread::PostTask(
611           BrowserThread::FILE,
612           FROM_HERE,
613           base::Bind(&MockCountListener::ShutdownOnFileThread,
614                      base::Unretained(this)));
615     }
616   }
617
618   void ShutdownOnFileThread() {
619     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
620     BrowserThread::PostTask(BrowserThread::UI,
621                             FROM_HERE,
622                             base::Bind(&MockCountListener::ShutdownOnUIThread,
623                                        base::Unretained(this)));
624   }
625
626   scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
627   int reposts_left_;
628   int invoked_;
629 };
630
631 class MockCountListenerWithReAdd : public MockCountListener {
632  public:
633   explicit MockCountListenerWithReAdd(
634       scoped_refptr<DevToolsAndroidBridge> adb_bridge)
635       : MockCountListener(adb_bridge),
636         readd_count_(2) {
637   }
638
639   void DeviceCountChanged(int count) override {
640     ++invoked_;
641     adb_bridge_->RemoveDeviceCountListener(this);
642     if (readd_count_ > 0) {
643       readd_count_--;
644       adb_bridge_->AddDeviceCountListener(this);
645       adb_bridge_->RemoveDeviceCountListener(this);
646       adb_bridge_->AddDeviceCountListener(this);
647     } else {
648       Shutdown();
649     }
650   }
651
652   int readd_count_;
653 };
654
655 class MockCountListenerWithReAddWhileQueued : public MockCountListener {
656  public:
657   MockCountListenerWithReAddWhileQueued(
658       scoped_refptr<DevToolsAndroidBridge> adb_bridge)
659       : MockCountListener(adb_bridge),
660         readded_(false) {
661   }
662
663   void DeviceCountChanged(int count) override {
664     ++invoked_;
665     if (!readded_) {
666       readded_ = true;
667       base::MessageLoop::current()->PostTask(
668           FROM_HERE,
669           base::Bind(&MockCountListenerWithReAddWhileQueued::ReAdd,
670                      base::Unretained(this)));
671     } else {
672       adb_bridge_->RemoveDeviceCountListener(this);
673       Shutdown();
674     }
675   }
676
677   void ReAdd() {
678     adb_bridge_->RemoveDeviceCountListener(this);
679     adb_bridge_->AddDeviceCountListener(this);
680   }
681
682   bool readded_;
683 };
684
685 class MockCountListenerForCheckingTraits : public MockCountListener {
686  public:
687   MockCountListenerForCheckingTraits(
688       scoped_refptr<DevToolsAndroidBridge> adb_bridge)
689       : MockCountListener(adb_bridge),
690         step_(0) {
691   }
692   void DeviceCountChanged(int count) override {
693     switch (step_) {
694       case 0:
695         // Check for 0 devices when no devices present.
696         EXPECT_EQ(0, count);
697         break;
698       case 1:
699         // Check for 1 device when only android device present.
700         EXPECT_EQ(1, count);
701         break;
702       case 2:
703         // Check for 1 device when android and non-android devices present.
704         EXPECT_EQ(1, count);
705         break;
706       case 3:
707         // Check for 0 devices when only non-android devices present.
708         EXPECT_EQ(0, count);
709         adb_bridge_->RemoveDeviceCountListener(this);
710         Shutdown();
711         break;
712       default:
713         EXPECT_TRUE(false) << "Unknown step " << step_;
714     }
715     step_++;
716   }
717
718   int step_;
719 };
720
721 }  // namespace
722
723 IN_PROC_BROWSER_TEST_F(AndroidUsbDiscoveryTest, TestDeviceDiscovery) {
724   MockListListener listener(adb_bridge_, runner_->QuitClosure());
725   adb_bridge_->AddDeviceListListener(&listener);
726   runner_->Run();
727 }
728
729 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
730                        TestNoMultipleCallsRemoveInCallback) {
731   MockCountListener listener(adb_bridge_);
732   adb_bridge_->AddDeviceCountListener(&listener);
733   runner_->Run();
734   EXPECT_EQ(1, listener.invoked_);
735   EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
736 }
737
738 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
739                        TestNoMultipleCallsRemoveAddInCallback) {
740   MockCountListenerWithReAdd listener(adb_bridge_);
741   adb_bridge_->AddDeviceCountListener(&listener);
742   runner_->Run();
743   EXPECT_EQ(3, listener.invoked_);
744   EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
745 }
746
747 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
748                        TestNoMultipleCallsRemoveAddOnStart) {
749   MockCountListener listener(adb_bridge_);
750   adb_bridge_->AddDeviceCountListener(&listener);
751   adb_bridge_->RemoveDeviceCountListener(&listener);
752   adb_bridge_->AddDeviceCountListener(&listener);
753   runner_->Run();
754   EXPECT_EQ(1, listener.invoked_);
755   EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
756 }
757
758 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
759                        TestNoMultipleCallsRemoveAddWhileQueued) {
760   MockCountListenerWithReAddWhileQueued listener(adb_bridge_);
761   adb_bridge_->AddDeviceCountListener(&listener);
762   runner_->Run();
763   EXPECT_EQ(2, listener.invoked_);
764   EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
765 }
766
767 IN_PROC_BROWSER_TEST_F(AndroidUsbTraitsTest, TestDeviceCounting) {
768   MockCountListenerForCheckingTraits listener(adb_bridge_);
769   adb_bridge_->AddDeviceCountListener(&listener);
770   runner_->Run();
771 }