diff --git a/lib/tools/adb-commands.js b/lib/tools/adb-commands.js index 3e1305a2..b8d06fcf 100644 --- a/lib/tools/adb-commands.js +++ b/lib/tools/adb-commands.js @@ -24,6 +24,11 @@ const HIDDEN_API_POLICY_KEYS = [ 'hidden_api_policy_p_apps', 'hidden_api_policy' ]; +const ANIMATION_SCALE_KEYS = [ + 'animator_duration_scale', + 'transition_animation_scale', + 'window_animation_scale' +]; const PID_COLUMN_TITLE = 'PID'; const PROCESS_NAME_COLUMN_TITLE = 'NAME'; const PS_TITLE_PATTERN = new RegExp(`^(.*\\b${PID_COLUMN_TITLE}\\b.*\\b${PROCESS_NAME_COLUMN_TITLE}\\b.*)$`, 'm'); @@ -958,18 +963,40 @@ methods.isDataOn = async function isDataOn () { }; /** - * Check the state of animation on the device under test. + * Check the state of animation on the device under test below: + * - animator_duration_scale + * - transition_animation_scale + * - window_animation_scale * * @this {import('../adb.js').ADB} * @return {Promise} True if at least one of animation scale settings * is not equal to '0.0'. */ methods.isAnimationOn = async function isAnimationOn () { - let animator_duration_scale = await this.getSetting('global', 'animator_duration_scale'); - let transition_animation_scale = await this.getSetting('global', 'transition_animation_scale'); - let window_animation_scale = await this.getSetting('global', 'window_animation_scale'); - return _.some([animator_duration_scale, transition_animation_scale, window_animation_scale], - (setting) => setting !== '0.0'); + return (await B.all(ANIMATION_SCALE_KEYS.map( + async (k) => (await this.getSetting('global', k)) !== '0.0')) + ).includes(true); +}; + +/** + * Set animation scale with the given value via adb shell settings command. + * - animator_duration_scale + * - transition_animation_scale + * - window_animation_scale + * API level 24 and newer OS versions may change the animation, at least emulators are so. + * API level 28+ real devices checked this worked, but we haven't checked older ones + * with real devices. + * + * @this {import('../adb.js').ADB} + * @param {number} value Animation scale value (int or float) to set. + * The minimum value of zero disables animations. + * By increasing the value, animations become slower. + * '1' is the system default animation scale. + * @return {Promise} + * @throws {Error} If the adb setting command raises an exception. + */ +methods.setAnimationScale = async function setAnimationScale (value) { + await B.all(ANIMATION_SCALE_KEYS.map((k) => this.setSetting('global', k, value))); }; /** diff --git a/test/unit/adb-commands-specs.js b/test/unit/adb-commands-specs.js index d4410bea..f13b5a81 100644 --- a/test/unit/adb-commands-specs.js +++ b/test/unit/adb-commands-specs.js @@ -11,6 +11,7 @@ import { EOL } from 'os'; chai.use(chaiAsPromised); +const expect = chai.expect; const should = chai.should(); const apiLevel = 21, platformVersion = '4.4.4', @@ -469,6 +470,32 @@ describe('adb commands', withMocks({adb, logcat, teen_process, net}, function (m (await adb.isAnimationOn()).should.be.true; }); }); + describe('setAnimation', function () { + it('should set 1/5 for 11/5', async function () { + mocks.adb.expects('setSetting').once().withExactArgs('global', 'animator_duration_scale', 1.5); + mocks.adb.expects('setSetting').once().withExactArgs('global', 'transition_animation_scale', 1.5); + mocks.adb.expects('setSetting').once().withExactArgs('global', 'window_animation_scale', 1.5); + expect(await adb.setAnimationScale(1.5)).not.throws; + }); + it('should set 1 for 1', async function () { + mocks.adb.expects('setSetting').once().withExactArgs('global', 'animator_duration_scale', 1); + mocks.adb.expects('setSetting').once().withExactArgs('global', 'transition_animation_scale', 1); + mocks.adb.expects('setSetting').once().withExactArgs('global', 'window_animation_scale', 1); + expect(await adb.setAnimationScale(1)).not.throws; + }); + it('should set 0 for 0', async function () { + mocks.adb.expects('setSetting').once().withExactArgs('global', 'animator_duration_scale', 0); + mocks.adb.expects('setSetting').once().withExactArgs('global', 'transition_animation_scale', 0); + mocks.adb.expects('setSetting').once().withExactArgs('global', 'window_animation_scale', 0); + expect(await adb.setAnimationScale(0)).not.throws; + }); + it('should set 0 for negative values', async function () { + mocks.adb.expects('setSetting').once().withExactArgs('global', 'animator_duration_scale', -1); + mocks.adb.expects('setSetting').once().withExactArgs('global', 'transition_animation_scale', -1); + mocks.adb.expects('setSetting').once().withExactArgs('global', 'window_animation_scale', -1); + expect(await adb.setAnimationScale(-1)).not.throws; + }); + }); describe('processExists', function () { it('should call shell with correct args and should find process', async function () { mocks.adb.expects('getPIDsByName')