Bug 1494549 - Show USB devices status in sidebar;r=ladybenko
authorJulian Descottes <jdescottes@mozilla.com>
Wed, 17 Oct 2018 11:10:05 +0000
changeset 500115 0fc18d6f9732fafe1261b8ef8794c624e0dbbdd0
parent 500114 e7995331d6386309dbe2caca5f947a54fc088249
child 500116 8bdb7699a04ccbc37827aa07fb98ad4d8937f303
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersladybenko
bugs1494549
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1494549 - Show USB devices status in sidebar;r=ladybenko Maybe we want to land the simplest solution for now and discuss quickly how to style the message to reduce confusion in a follow up? Differential Revision: https://phabricator.services.mozilla.com/D8334
devtools/client/aboutdebugging-new/aboutdebugging.js
devtools/client/aboutdebugging-new/src/actions/ui.js
devtools/client/aboutdebugging-new/src/components/App.js
devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.css
devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js
devtools/client/aboutdebugging-new/src/constants.js
devtools/client/aboutdebugging-new/src/reducers/ui-state.js
devtools/client/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl
--- a/devtools/client/aboutdebugging-new/aboutdebugging.js
+++ b/devtools/client/aboutdebugging-new/aboutdebugging.js
@@ -29,28 +29,31 @@ const {
 const {
   addUSBRuntimesObserver,
   disableUSBRuntimes,
   enableUSBRuntimes,
   getUSBRuntimes,
   removeUSBRuntimesObserver,
 } = require("./src/modules/usb-runtimes");
 
+loader.lazyRequireGetter(this, "adbAddon", "devtools/shared/adb/adb-addon", true);
+
 const App = createFactory(require("./src/components/App"));
 
 const { PAGES, RUNTIMES } = require("./src/constants");
 
 const AboutDebugging = {
   async init() {
     if (!Services.prefs.getBoolPref("devtools.enabled", true)) {
       // If DevTools are disabled, navigate to about:devtools.
       window.location = "about:devtools?reason=AboutDebugging";
       return;
     }
 
+    this.onAdbAddonUpdated = this.onAdbAddonUpdated.bind(this);
     this.onNetworkLocationsUpdated = this.onNetworkLocationsUpdated.bind(this);
     this.onUSBRuntimesUpdated = this.onUSBRuntimesUpdated.bind(this);
 
     this.store = configureStore();
     this.actions = bindActionCreators(actions, this.store.dispatch);
 
     const messageContexts = await this.createMessageContexts();
 
@@ -60,16 +63,19 @@ const AboutDebugging = {
     );
 
     this.actions.selectPage(PAGES.THIS_FIREFOX, RUNTIMES.THIS_FIREFOX);
     this.actions.updateNetworkLocations(getNetworkLocations());
 
     addNetworkLocationsObserver(this.onNetworkLocationsUpdated);
     addUSBRuntimesObserver(this.onUSBRuntimesUpdated);
     await enableUSBRuntimes();
+
+    adbAddon.on("update", this.onAdbAddonUpdated);
+    this.onAdbAddonUpdated();
   },
 
   async createMessageContexts() {
     // XXX Until the strings for the updated about:debugging stabilize, we
     // locate them outside the regular directory for locale resources so that
     // they don't get picked up by localization tools.
     if (!L10nRegistry.sources.has("aboutdebugging")) {
       const temporarySource = new FileSource(
@@ -87,16 +93,20 @@ const AboutDebugging = {
     const contexts = [];
     for await (const context of generator) {
       contexts.push(context);
     }
 
     return contexts;
   },
 
+  onAdbAddonUpdated() {
+    this.actions.updateAdbAddonStatus(adbAddon.status);
+  },
+
   onNetworkLocationsUpdated() {
     this.actions.updateNetworkLocations(getNetworkLocations());
   },
 
   onUSBRuntimesUpdated() {
     this.actions.updateUSBRuntimes(getUSBRuntimes());
   },
 
@@ -108,16 +118,17 @@ const AboutDebugging = {
     const currentRuntimeId = state.runtimes.selectedRuntimeId;
     if (currentRuntimeId) {
       await this.actions.unwatchRuntime(currentRuntimeId);
     }
 
     removeNetworkLocationsObserver(this.onNetworkLocationsUpdated);
     removeUSBRuntimesObserver(this.onUSBRuntimesUpdated);
     disableUSBRuntimes();
+    adbAddon.off("update", this.onAdbAddonUpdated);
     setDebugTargetCollapsibilities(state.ui.debugTargetCollapsibilities);
     unmountComponentAtNode(this.mount);
   },
 
   get mount() {
     return document.getElementById("mount");
   },
 };
--- a/devtools/client/aboutdebugging-new/src/actions/ui.js
+++ b/devtools/client/aboutdebugging-new/src/actions/ui.js
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {
+  ADB_ADDON_STATUS_UPDATED,
   DEBUG_TARGET_COLLAPSIBILITY_UPDATED,
   NETWORK_LOCATIONS_UPDATED,
   PAGE_SELECTED,
   PAGES,
 } = require("../constants");
 
 const NetworkLocationsModule = require("../modules/network-locations");
 
@@ -55,19 +56,24 @@ function addNetworkLocation(location) {
 }
 
 function removeNetworkLocation(location) {
   return (dispatch, getState) => {
     NetworkLocationsModule.removeNetworkLocation(location);
   };
 }
 
+function updateAdbAddonStatus(adbAddonStatus) {
+  return { type: ADB_ADDON_STATUS_UPDATED, adbAddonStatus };
+}
+
 function updateNetworkLocations(locations) {
   return { type: NETWORK_LOCATIONS_UPDATED, locations };
 }
 
 module.exports = {
   addNetworkLocation,
   removeNetworkLocation,
   selectPage,
+  updateAdbAddonStatus,
   updateDebugTargetCollapsibility,
   updateNetworkLocations,
 };
--- a/devtools/client/aboutdebugging-new/src/components/App.js
+++ b/devtools/client/aboutdebugging-new/src/components/App.js
@@ -16,16 +16,17 @@ const { PAGES } = require("../constants"
 
 const ConnectPage = createFactory(require("./connect/ConnectPage"));
 const RuntimePage = createFactory(require("./RuntimePage"));
 const Sidebar = createFactory(require("./sidebar/Sidebar"));
 
 class App extends PureComponent {
   static get propTypes() {
     return {
+      adbAddonStatus: PropTypes.string,
       // The "dispatch" helper is forwarded to the App component via connect.
       // From that point, components are responsible for forwarding the dispatch
       // property to all components who need to dispatch actions.
       dispatch: PropTypes.func.isRequired,
       messageContexts: PropTypes.arrayOf(PropTypes.object).isRequired,
       networkLocations: PropTypes.arrayOf(PropTypes.string).isRequired,
       runtimes: PropTypes.object.isRequired,
       selectedPage: PropTypes.string,
@@ -46,38 +47,48 @@ class App extends PureComponent {
       default:
         // All pages except for the CONNECT page are RUNTIME pages.
         return RuntimePage({ dispatch });
     }
   }
 
   render() {
     const {
+      adbAddonStatus,
       dispatch,
       messageContexts,
       runtimes,
       selectedPage,
     } = this.props;
 
     return LocalizationProvider(
       { messages: messageContexts },
       dom.div(
         { className: "app" },
-        Sidebar({ className: "app__sidebar", dispatch, runtimes, selectedPage }),
+        Sidebar(
+          {
+            adbAddonStatus,
+            className: "app__sidebar",
+            dispatch,
+            runtimes,
+            selectedPage
+          }
+        ),
         dom.main(
           { className: "app__content" },
           this.getSelectedPageComponent()
         )
       )
     );
   }
 }
 
 const mapStateToProps = state => {
   return {
+    adbAddonStatus: state.ui.adbAddonStatus,
     runtimes: state.runtimes,
     networkLocations: state.ui.networkLocations,
     selectedPage: state.ui.selectedPage,
   };
 };
 
 const mapDispatchToProps = dispatch => ({
   dispatch,
--- a/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.css
+++ b/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.css
@@ -1,11 +1,11 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-.sidebar__devices__no-devices-message {
+.sidebar__devices__message {
   color: var(--grey-40);
   display: inline-block;
   padding: 12px 0;
   text-align: center;
   width: 100%;
 }
\ No newline at end of file
--- a/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js
+++ b/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js
@@ -7,43 +7,61 @@
 const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
 const FluentReact = require("devtools/client/shared/vendor/fluent-react");
 const Localized = createFactory(FluentReact.Localized);
 
 const { PAGES, RUNTIMES } = require("../../constants");
+loader.lazyRequireGetter(this, "ADB_ADDON_STATES", "devtools/shared/adb/adb-addon", true);
 
 const SidebarFixedItem = createFactory(require("./SidebarFixedItem"));
 const SidebarRuntimeItem = createFactory(require("./SidebarRuntimeItem"));
 const FIREFOX_ICON = "chrome://devtools/skin/images/aboutdebugging-firefox-logo.svg";
 const CONNECT_ICON = "chrome://devtools/skin/images/aboutdebugging-connect-icon.svg";
 const GLOBE_ICON = "chrome://devtools/skin/images/aboutdebugging-globe-icon.svg";
 const USB_ICON = "chrome://devtools/skin/images/aboutdebugging-connect-icon.svg";
 
 class Sidebar extends PureComponent {
   static get propTypes() {
     return {
+      adbAddonStatus: PropTypes.string,
       className: PropTypes.string,
       dispatch: PropTypes.func.isRequired,
       runtimes: PropTypes.object.isRequired,
       selectedPage: PropTypes.string,
     };
   }
 
+  renderAdbAddonStatus() {
+    const isAddonInstalled = this.props.adbAddonStatus === ADB_ADDON_STATES.INSTALLED;
+    const localizationId = isAddonInstalled ? "about-debugging-sidebar-usb-enabled" :
+                                              "about-debugging-sidebar-usb-disabled";
+    return Localized(
+      {
+        id: localizationId
+      }, dom.aside(
+        {
+          className: "sidebar__devices__message"
+        },
+        localizationId
+      )
+    );
+  }
+
   renderDevices() {
     const { runtimes } = this.props;
     if (!runtimes.networkRuntimes.length && !runtimes.usbRuntimes.length) {
       return Localized(
         {
           id: "about-debugging-sidebar-no-devices"
-        }, dom.span(
+        }, dom.aside(
           {
-            className: "sidebar__devices__no-devices-message js-sidebar-no-devices"
+            className: "sidebar__devices__message js-sidebar-no-devices"
           },
           "No devices discovered"
         )
       );
     }
 
     return [
       ...this.renderSidebarItems(GLOBE_ICON, runtimes.networkRuntimes),
@@ -98,15 +116,16 @@ class Sidebar extends PureComponent {
             id: PAGES.CONNECT,
             dispatch,
             icon: CONNECT_ICON,
             isSelected: PAGES.CONNECT === selectedPage,
             name: "Connect",
           })
         ),
         dom.hr(),
+        this.renderAdbAddonStatus(),
         this.renderDevices()
       )
     );
   }
 }
 
 module.exports = Sidebar;
--- a/devtools/client/aboutdebugging-new/src/constants.js
+++ b/devtools/client/aboutdebugging-new/src/constants.js
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const actionTypes = {
+  ADB_ADDON_STATUS_UPDATED: "ADB_ADDON_STATUS_UPDATED",
   CONNECT_RUNTIME_FAILURE: "CONNECT_RUNTIME_FAILURE",
   CONNECT_RUNTIME_START: "CONNECT_RUNTIME_START",
   CONNECT_RUNTIME_SUCCESS: "CONNECT_RUNTIME_SUCCESS",
   DEBUG_TARGET_COLLAPSIBILITY_UPDATED: "DEBUG_TARGET_COLLAPSIBILITY_UPDATED",
   DISCONNECT_RUNTIME_FAILURE: "DISCONNECT_RUNTIME_FAILURE",
   DISCONNECT_RUNTIME_START: "DISCONNECT_RUNTIME_START",
   DISCONNECT_RUNTIME_SUCCESS: "DISCONNECT_RUNTIME_SUCCESS",
   NETWORK_LOCATIONS_UPDATED: "NETWORK_LOCATIONS_UPDATED",
--- a/devtools/client/aboutdebugging-new/src/reducers/ui-state.js
+++ b/devtools/client/aboutdebugging-new/src/reducers/ui-state.js
@@ -1,30 +1,37 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {
+  ADB_ADDON_STATUS_UPDATED,
   DEBUG_TARGET_COLLAPSIBILITY_UPDATED,
   NETWORK_LOCATIONS_UPDATED,
   PAGE_SELECTED,
 } = require("../constants");
 
 function UiState(locations = [], debugTargetCollapsibilities = {}) {
   return {
+    adbAddonStatus: null,
     debugTargetCollapsibilities,
     networkLocations: locations,
     selectedPage: null,
   };
 }
 
 function uiReducer(state = UiState(), action) {
   switch (action.type) {
+    case ADB_ADDON_STATUS_UPDATED: {
+      const { adbAddonStatus } = action;
+      return Object.assign({}, state, { adbAddonStatus });
+    }
+
     case DEBUG_TARGET_COLLAPSIBILITY_UPDATED: {
       const { isCollapsed, key } = action;
       const debugTargetCollapsibilities = new Map(state.debugTargetCollapsibilities);
       debugTargetCollapsibilities.set(key, isCollapsed);
       return Object.assign({}, state, { debugTargetCollapsibilities });
     }
 
     case NETWORK_LOCATIONS_UPDATED: {
--- a/devtools/client/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl
+++ b/devtools/client/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl
@@ -8,16 +8,23 @@
 # Sidebar heading for selecting the currently running instance of Firefox
 about-debugging-sidebar-this-firefox =
   .name = This Firefox
 
 # Sidebar heading for connecting to some remote source
 about-debugging-sidebar-connect =
   .name = Connect
 
+# Text displayed in the about:debugging sidebar when USB devices discovery is enabled.
+about-debugging-sidebar-usb-enabled = USB devices enabled
+
+# Text displayed in the about:debugging sidebar when USB devices discovery is disabled
+# (for instance because the mandatory ADB extension is not installed).
+about-debugging-sidebar-usb-disabled = USB devices disabled
+
 # Connection status (connected) for runtime items in the sidebar
 aboutdebugging-sidebar-runtime-connection-status-connected = Connected
 # Connection status (disconnected) for runtime items in the sidebar
 aboutdebugging-sidebar-runtime-connection-status-disconnected = Disconnected
 
 # Text displayed in the about:debugging sidebar when no device was found.
 about-debugging-sidebar-no-devices = No devices discovered