diff --git a/src/chrome/DevicesButton.js b/src/chrome/DevicesButton.js index ac9165772..0a4e0b62d 100644 --- a/src/chrome/DevicesButton.js +++ b/src/chrome/DevicesButton.js @@ -6,7 +6,6 @@ */ import {Component, Button, styled} from 'flipper'; -import ArchivedDevice from '../devices/ArchivedDevice.js'; import {connect} from 'react-redux'; import {spawn} from 'child_process'; import {dirname} from 'path'; @@ -65,7 +64,7 @@ class DevicesButton extends Component { let buttonLabel = 'No device selected'; let icon = 'minus-circle'; - if (selectedDevice instanceof ArchivedDevice) { + if (selectedDevice?.isArchived) { buttonLabel = `${selectedDevice?.title || 'Unknown device'} (offline)`; icon = 'box'; } else if (selectedDevice?.deviceType === 'physical') { @@ -117,11 +116,11 @@ class DevicesButton extends Component { // Archived const importedFiles = [ { - label: 'Imported Devices', + label: 'Disconnected Devices', enabled: false, }, ...devices - .filter(device => device instanceof ArchivedDevice) + .filter(device => device.isArchived) .map((device: BaseDevice) => ({ click: () => selectDevice(device), checked: device === selectedDevice, @@ -137,8 +136,10 @@ class DevicesButton extends Component { const emulators = Array.from(androidEmulators) .filter( (name: string) => - devices.findIndex((device: BaseDevice) => device.title === name) === - -1, + devices.findIndex( + (device: BaseDevice) => + device.title === name && !device.isArchived, + ) === -1, ) .map((name: string) => ({ label: name, diff --git a/src/devices/AndroidDevice.js b/src/devices/AndroidDevice.js index 24b5ac850..0c48b39c5 100644 --- a/src/devices/AndroidDevice.js +++ b/src/devices/AndroidDevice.js @@ -11,6 +11,7 @@ import {Priority} from 'adbkit-logcat-fb'; import child_process from 'child_process'; import child_process_promise from 'child-process-es6-promise'; import BaseDevice from './BaseDevice.js'; +import ArchivedDevice from './ArchivedDevice.js'; type ADBClient = any; @@ -85,4 +86,14 @@ export default class AndroidDevice extends BaseDevice { clearLogs(): Promise { return child_process_promise.spawn('adb', ['logcat', '-c']); } + + archive(): ArchivedDevice { + return new ArchivedDevice( + this.serial, + this.deviceType, + this.title, + this.os, + [...this.logEntries], + ); + } } diff --git a/src/devices/ArchivedDevice.js b/src/devices/ArchivedDevice.js index 1ae4bd47e..faf324583 100644 --- a/src/devices/ArchivedDevice.js +++ b/src/devices/ArchivedDevice.js @@ -33,6 +33,8 @@ export default class ArchivedDevice extends BaseDevice { logs: Array; + isArchived = true; + getLogs() { return this.logs; } diff --git a/src/devices/BaseDevice.js b/src/devices/BaseDevice.js index 93e2d80c7..c44eb5e9a 100644 --- a/src/devices/BaseDevice.js +++ b/src/devices/BaseDevice.js @@ -6,6 +6,7 @@ */ import type stream from 'stream'; +import type ArchivedDevice from './ArchivedDevice'; export type LogLevel = | 'unknown' @@ -74,6 +75,7 @@ export default class BaseDevice { logListeners: Map = new Map(); logEntries: Array = []; + isArchived: boolean = false; supportsOS(os: OS) { return os.toLowerCase() === this.os.toLowerCase(); @@ -135,4 +137,8 @@ export default class BaseDevice { spawnShell(): ?DeviceShell { throw new Error('unimplemented'); } + + archive(): ?ArchivedDevice { + return null; + } } diff --git a/src/dispatcher/androidDevice.js b/src/dispatcher/androidDevice.js index 434e0b6e9..64b3c65d2 100644 --- a/src/dispatcher/androidDevice.js +++ b/src/dispatcher/androidDevice.js @@ -158,6 +158,21 @@ export default (store: Store, logger: Logger) => { name: androidDevice.title, serial: androidDevice.serial, }); + + // remove offline devices with same serial as the connected. + const reconnectedDevices = store + .getState() + .connections.devices.filter( + (device: BaseDevice) => + device.serial === androidDevice.serial && device.isArchived, + ) + .map(device => device.serial); + + store.dispatch({ + type: 'UNREGISTER_DEVICES', + payload: new Set(reconnectedDevices), + }); + store.dispatch({ type: 'REGISTER_DEVICE', payload: androidDevice, @@ -178,10 +193,29 @@ export default (store: Store, logger: Logger) => { serial: id, }), ); + + const archivedDevices = deviceIds + .map(id => { + const device = store + .getState() + .connections.devices.find(device => device.serial === id); + if (device && !device.isArchived) { + return device.archive(); + } + }) + .filter(Boolean); + store.dispatch({ type: 'UNREGISTER_DEVICES', payload: new Set(deviceIds), }); + + archivedDevices.forEach((payload: BaseDevice) => + store.dispatch({ + type: 'REGISTER_DEVICE', + payload, + }), + ); } watchAndroidDevices();