Reland "[Lighthouse] Rename Audits panel to Lighthouse"

This reverts commit 065146856295c7ebf01d538820d3f2e60c383335.

Reason for revert: Cause of failure has been remedied. See: https://chromium-review.googlesource.com/c/chromium/src/+/2055398

Original change's description:
> Revert "[Lighthouse] Rename Audits panel to Lighthouse"
>
> This reverts commit 2ae53ef04d84c4201836eb63238e97bc180ea54d.
>
> Reason for revert: This CL breaks CI: https://ci.chromium.org/p/devtools-frontend/builders/ci/DevTools%20Linux/453. It looks like the layout test expects audits not lighthouse in the name, so it's probably in need of a 3-way merge.
>
> Original change's description:
> > [Lighthouse] Rename Audits panel to Lighthouse
> >
> > Change-Id: Ia2ab175d2a3b6c8ded73aff8ff0f5582f5a8fa0c
> > Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2044605
> > Commit-Queue: Connor Clark <cjamcl@chromium.org>
> > Reviewed-by: Tim van der Lippe <tvanderlippe@chromium.org>
> > Reviewed-by: Paul Irish <paulirish@chromium.org>
>
> TBR=paulirish@chromium.org,aerotwist@chromium.org,tvanderlippe@chromium.org,cjamcl@chromium.org
>
> Change-Id: Ia6d5f42a0e6ece4352696c51bf0de5754774cb0a
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2051983
> Reviewed-by: Paul Lewis <aerotwist@chromium.org>
> Commit-Queue: Paul Lewis <aerotwist@chromium.org>

TBR=paulirish@chromium.org,aerotwist@chromium.org,tvanderlippe@chromium.org,cjamcl@chromium.org

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: 1052111
Change-Id: I638ca9bd5cd94e02fb7318f2a7d7c66fca40e6c8
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2056866
Reviewed-by: Connor Clark <cjamcl@chromium.org>
Reviewed-by: Paul Irish <paulirish@chromium.org>
Reviewed-by: Tim van der Lippe <tvanderlippe@chromium.org>
Commit-Queue: Connor Clark <cjamcl@chromium.org>
diff --git a/front_end/lighthouse/LighthouseController.js b/front_end/lighthouse/LighthouseController.js
new file mode 100644
index 0000000..c951078
--- /dev/null
+++ b/front_end/lighthouse/LighthouseController.js
@@ -0,0 +1,289 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @implements {SDK.SDKModelObserver<!SDK.ServiceWorkerManager>}
+ * @unrestricted
+ */
+export class LighthouseController extends Common.Object {
+  constructor(protocolService) {
+    super();
+
+    protocolService.registerStatusCallback(
+        message => this.dispatchEventToListeners(Events.AuditProgressChanged, {message}));
+
+    for (const preset of Presets) {
+      preset.setting.addChangeListener(this.recomputePageAuditability.bind(this));
+    }
+
+    self.SDK.targetManager.observeModels(SDK.ServiceWorkerManager, this);
+    self.SDK.targetManager.addEventListener(
+        SDK.TargetManager.Events.InspectedURLChanged, this.recomputePageAuditability, this);
+  }
+
+  /**
+   * @override
+   * @param {!SDK.ServiceWorkerManager} serviceWorkerManager
+   */
+  modelAdded(serviceWorkerManager) {
+    if (this._manager) {
+      return;
+    }
+
+    this._manager = serviceWorkerManager;
+    this._serviceWorkerListeners = [
+      this._manager.addEventListener(
+          SDK.ServiceWorkerManager.Events.RegistrationUpdated, this.recomputePageAuditability, this),
+      this._manager.addEventListener(
+          SDK.ServiceWorkerManager.Events.RegistrationDeleted, this.recomputePageAuditability, this),
+    ];
+
+    this.recomputePageAuditability();
+  }
+
+  /**
+   * @override
+   * @param {!SDK.ServiceWorkerManager} serviceWorkerManager
+   */
+  modelRemoved(serviceWorkerManager) {
+    if (this._manager !== serviceWorkerManager) {
+      return;
+    }
+
+    Common.EventTarget.removeEventListeners(this._serviceWorkerListeners);
+    this._manager = null;
+    this.recomputePageAuditability();
+  }
+
+  /**
+   * @return {boolean}
+   */
+  _hasActiveServiceWorker() {
+    if (!this._manager) {
+      return false;
+    }
+
+    const mainTarget = this._manager.target();
+    if (!mainTarget) {
+      return false;
+    }
+
+    const inspectedURL = Common.ParsedURL.fromString(mainTarget.inspectedURL());
+    const inspectedOrigin = inspectedURL && inspectedURL.securityOrigin();
+    for (const registration of this._manager.registrations().values()) {
+      if (registration.securityOrigin !== inspectedOrigin) {
+        continue;
+      }
+
+      for (const version of registration.versions.values()) {
+        if (version.controlledClients.length > 1) {
+          return true;
+        }
+      }
+    }
+
+    return false;
+  }
+
+  /**
+   * @return {boolean}
+   */
+  _hasAtLeastOneCategory() {
+    return Presets.some(preset => preset.setting.get());
+  }
+
+  /**
+   * @return {?string}
+   */
+  _unauditablePageMessage() {
+    if (!this._manager) {
+      return null;
+    }
+
+    const mainTarget = this._manager.target();
+    const inspectedURL = mainTarget && mainTarget.inspectedURL();
+    if (inspectedURL && !/^(http|chrome-extension)/.test(inspectedURL)) {
+      return Common.UIString(
+          'Can only audit HTTP/HTTPS pages and Chrome extensions. Navigate to a different page to start an audit.');
+    }
+
+    return null;
+  }
+
+  /**
+   * @return {!Promise<string>}
+   */
+  async _evaluateInspectedURL() {
+    const mainTarget = this._manager.target();
+    const runtimeModel = mainTarget.model(SDK.RuntimeModel);
+    const executionContext = runtimeModel && runtimeModel.defaultExecutionContext();
+    let inspectedURL = mainTarget.inspectedURL();
+    if (!executionContext) {
+      return inspectedURL;
+    }
+
+    // Evaluate location.href for a more specific URL than inspectedURL provides so that SPA hash navigation routes
+    // will be respected and audited.
+    try {
+      const result = await executionContext.evaluate(
+          {
+            expression: 'window.location.href',
+            objectGroup: 'lighthouse',
+            includeCommandLineAPI: false,
+            silent: false,
+            returnByValue: true,
+            generatePreview: false
+          },
+          /* userGesture */ false, /* awaitPromise */ false);
+      if (!result.exceptionDetails && result.object) {
+        inspectedURL = result.object.value;
+        result.object.release();
+      }
+    } catch (err) {
+      console.error(err);
+    }
+
+    return inspectedURL;
+  }
+
+  /**
+   * @return {!Object}
+   */
+  getFlags() {
+    const flags = {
+      // DevTools handles all the emulation. This tells Lighthouse to not bother with emulation.
+      internalDisableDeviceScreenEmulation: true
+    };
+    for (const runtimeSetting of RuntimeSettings) {
+      runtimeSetting.setFlags(flags, runtimeSetting.setting.get());
+    }
+    return flags;
+  }
+
+  /**
+   * @return {!Array<string>}
+   */
+  getCategoryIDs() {
+    const categoryIDs = [];
+    for (const preset of Presets) {
+      if (preset.setting.get()) {
+        categoryIDs.push(preset.configID);
+      }
+    }
+    return categoryIDs;
+  }
+
+  /**
+   * @param {{force: boolean}=} options
+   * @return {!Promise<string>}
+   */
+  async getInspectedURL(options) {
+    if (options && options.force || !this._inspectedURL) {
+      this._inspectedURL = await this._evaluateInspectedURL();
+    }
+    return this._inspectedURL;
+  }
+
+  recomputePageAuditability() {
+    const hasActiveServiceWorker = this._hasActiveServiceWorker();
+    const hasAtLeastOneCategory = this._hasAtLeastOneCategory();
+    const unauditablePageMessage = this._unauditablePageMessage();
+
+    let helpText = '';
+    if (hasActiveServiceWorker) {
+      helpText = Common.UIString(
+          'Multiple tabs are being controlled by the same service worker. Close your other tabs on the same origin to audit this page.');
+    } else if (!hasAtLeastOneCategory) {
+      helpText = Common.UIString('At least one category must be selected.');
+    } else if (unauditablePageMessage) {
+      helpText = unauditablePageMessage;
+    }
+
+    this.dispatchEventToListeners(Events.PageAuditabilityChanged, {helpText});
+  }
+}
+
+/** @type {!Array.<!Lighthouse.Preset>} */
+export const Presets = [
+  // configID maps to Lighthouse's Object.keys(config.categories)[0] value
+  {
+    setting: self.Common.settings.createSetting('lighthouse.cat_perf', true),
+    configID: 'performance',
+    title: ls`Performance`,
+    description: ls`How long does this app take to show content and become usable`
+  },
+  {
+    setting: self.Common.settings.createSetting('lighthouse.cat_pwa', true),
+    configID: 'pwa',
+    title: ls`Progressive Web App`,
+    description: ls`Does this page meet the standard of a Progressive Web App`
+  },
+  {
+    setting: self.Common.settings.createSetting('lighthouse.cat_best_practices', true),
+    configID: 'best-practices',
+    title: ls`Best practices`,
+    description: ls`Does this page follow best practices for modern web development`
+  },
+  {
+    setting: self.Common.settings.createSetting('lighthouse.cat_a11y', true),
+    configID: 'accessibility',
+    title: ls`Accessibility`,
+    description: ls`Is this page usable by people with disabilities or impairments`
+  },
+  {
+    setting: self.Common.settings.createSetting('lighthouse.cat_seo', true),
+    configID: 'seo',
+    title: ls`SEO`,
+    description: ls`Is this page optimized for search engine results ranking`
+  },
+  {
+    setting: self.Common.settings.createSetting('lighthouse.cat_pubads', false),
+    plugin: true,
+    configID: 'lighthouse-plugin-publisher-ads',
+    title: ls`Publisher Ads`,
+    description: ls`Is this page optimized for ad speed and quality`
+  },
+];
+
+/** @type {!Array.<!Lighthouse.RuntimeSetting>} */
+export const RuntimeSettings = [
+  {
+    setting: self.Common.settings.createSetting('lighthouse.device_type', 'mobile'),
+    description: ls`Apply mobile emulation during auditing`,
+    setFlags: (flags, value) => {
+      // See Audits.AuditsPanel._setupEmulationAndProtocolConnection()
+      flags.emulatedFormFactor = value;
+    },
+    options: [
+      {label: ls`Mobile`, value: 'mobile'},
+      {label: ls`Desktop`, value: 'desktop'},
+    ],
+  },
+  {
+    // This setting is disabled, but we keep it around to show in the UI.
+    setting: self.Common.settings.createSetting('lighthouse.throttling', true),
+    title: ls`Simulated throttling`,
+    // We will disable this when we have a Lantern trace viewer within DevTools.
+    learnMore:
+        'https://github.com/GoogleChrome/lighthouse/blob/master/docs/throttling.md#devtools-lighthouse-panel-throttling',
+    setFlags: (flags, value) => {
+      flags.throttlingMethod = value ? 'simulate' : 'devtools';
+    },
+  },
+  {
+    setting: self.Common.settings.createSetting('lighthouse.clear_storage', true),
+    title: ls`Clear storage`,
+    description: ls`Reset storage (localStorage, IndexedDB, etc) before auditing. (Good for performance & PWA testing)`,
+    setFlags: (flags, value) => {
+      flags.disableStorageReset = !value;
+    },
+  },
+];
+
+export const Events = {
+  PageAuditabilityChanged: Symbol('PageAuditabilityChanged'),
+  AuditProgressChanged: Symbol('AuditProgressChanged'),
+  RequestLighthouseStart: Symbol('RequestLighthouseStart'),
+  RequestLighthouseCancel: Symbol('RequestLighthouseCancel'),
+};