adb命令实现一些有趣的功能

下载ADB工具集,手机连接电脑后,用Windows自带命令行进入ADB工具,输入以下命令即可免root实现神奇功能

1.电量显示:

adb shell content insert --uri content://settings/system --bind name:s:status_bar_show_battery_percent --bind value:i:1

2.全屏沉浸:

adb shell settings put global policy_control immersive.full=*

3.沉浸状态栏:

adb shell settings put global policy_control immersive.status=*

4.沉浸导航栏:

adb shell settings put global policy_control immersive.navigation=*

5.我们还可以单独控制哪些app不沉浸,例如以下代码设置google即时桌面不沉浸,其他程序沉浸:

adb shell settings put global policy_control immersive.full=apps,-com.google.android.googlequicksearchbox

6.如果想恢复到正常模式,运行下面的代码:

adb shell settings put global policy_control null

7.截图命令screencap

 adb shell screencap -p /sdcard/screen.png

8.命令行下拉和收缩状态栏

adb shell service call statusbar 1       //下拉显示命令行
adb shell service call statusbar 2       //收缩状态栏

在nexus6吧发现了上面这个帖子,感谢nexus6吧的机友,亲测可用,很强大,可以正常使用输入法,使用虚拟按键时从底部上滑即可,比贴吧里那个使用全能助手隐藏虚拟键的方法好些,adb工具用刷机精灵也可以,我是把第四条和第五条命令综合一下,nova启动器不隐藏虚拟键,其他全部隐藏虚拟键,但状态栏都不隐藏,指令:

adb shell settings put global policy_control immersive.navigation=apps,-com.teslacoilsw.launcher

adb shell settings put global policy_control immersive.navigation=apps,-com.teslacoilsw.launcher,-com.motorola.camera 

由于机友反映打开相机无法呼出虚拟键,今天把指令改进了一下,这个adb指令可以让nova启动器和moto相机都不隐藏虚拟键,从而解决了隐藏虚拟键后打开相机上滑无法呼出虚拟键。

moto z/z play按一下指纹键就可以自动呼出虚拟键,不用上滑呼出的,所以,这种方法还是可以的,不用root,不影响OTA和保修。

(注意:1.adb工具也可以下载刷机精灵,使用其工具中的adb命令行;2.输入adb命令时记得切换到英文;3.apps后面的文件名,可以在手机上打开,然后去设置中的正在运行的程序中查看,或者下载安装文件名查看器查看 )

adb shell am 的用法

C:\Users\Administrator>adb shell am
usage: am [subcommand] [options]

start an Activity: am start [-D] [-W] 
    -D: enable debugging
    -W: wait for launch to complete

start a Service: am startservice 

send a broadcast Intent: am broadcast 

start an Instrumentation: am instrument [flags] 
    -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT)
    -e  : set argument  to 
    -p : write profiling data to 
    -w: wait for instrumentation to finish before returning

start profiling: am profile  start 
stop profiling: am profile  stop

start monitoring: am monitor [--gdb ]
    --gdb: start gdbserv on the given port at crash/ANR

 specifications include these flags:
    [-a ] [-d ] [-t ]
    [-c  [-c ] ...]
    [-e|--es   ...]
    [--esn  ...]
    [--ez   ...]
    [-e|--ei   ...]
    [-n ] [-f ]
    [--grant-read-uri-permission] [--grant-write-uri-permission]
    [--debug-log-resolution]
    [--activity-brought-to-front] [--activity-clear-top]
    [--activity-clear-when-task-reset] [--activity-exclude-from-recents]
    [--activity-launched-from-history] [--activity-multiple-task]
    [--activity-no-animation] [--activity-no-history]
    [--activity-no-user-action] [--activity-previous-is-top]
    [--activity-reorder-to-front] [--activity-reset-task-if-needed]
    [--activity-single-top]
    [--receiver-registered-only] [--receiver-replace-pending]
    []

使用实例:
如启动一个 Activity:

格式:

adb shell am start -n 包名/包名+类名(-n 类名,-a action,-d date,-m MIME-TYPE,-c category,-e 扩展数据,等)。

实例1:

C:\Users\Administrator>adb shell am start -n com.android.camera/.Camera
Starting: Intent { cmp=com.android.camera/.Camera }

实例2:(带extra 的 intent)

C:\Users\Administrator>adb shell am start -n com.android.camera/.Camera -e abc hello

Starting: Intent { cmp=com.android.camera/.Camera (has extras) }
其中 extra 的 key 为 abc ,value 为字串 "hello"

还可以发送命令模拟手机低电环境:
实例:

adb shell am broadcast -a android.intent.action.BATTERY_CHANGED --ei "level" 3 --ei "scale" 100

ANDROID: 设置显示窗口的SIZE和DENSITY

Android系统中有一个wm命令,可以设置显示窗口的尺寸(重新设置屏幕的罗辑分辩率)和屏幕的dpi。

设置显示窗口的尺寸

$ adb shell wm size 540x960

显示窗口的尺寸可以比屏幕的物理分辨率大,也可以比它小。重置用如下命令:

$ adb shell wm size reset

设置完之后,你会发现SurfaceFlinger中的Layer的尺寸也发生的变化。
以Nexus4为例,原来Live Wallpaper: PhaseBeam Layer的尺寸为768×1280:

$ adb shell dumpsys SurfaceFlinger
...
+ Layer 0xb7bbf3b0 (com.android.phasebeam.PhaseBeamWallpaper)
  Region transparentRegion (this=0xb7bbf510, count=1)
    [  0,   0,   0,   0]
  Region visibleRegion (this=0xb7bbf3b8, count=1)
    [  0,  50, 768, 1184]
      layerStack=   0, z=    21000, pos=(0,0), size=( 768,1280), crop=(   0,  50, 768,1184), isOpaque=1, invalidate=0, alpha=0xff, flags=0x00000002, tr=[1.00, 0.00][0.00, 1.00]
      client=0xb7bad728
      format= 2, activeBuffer=[ 768x1280: 768,  3], queued-frames=0, mRefreshPending=0
            mTexName=10 mCurrentTexture=0
            mCurrentCrop=[0,0,0,0] mCurrentTransform=0
            mAbandoned=0
        -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[768x1280], default-format=2, transform-hint=00, FIFO(0)={}
            >[00:0xb7bbef08] state=ACQUIRED, 0xb7b18260 [ 768x1280: 768,  3]
             [01:0xb7baf328] state=FREE    , 0xb7badaa8 [ 768x1280: 768,  3]
             [02:0xb7b1a5d0] state=FREE    , 0xb7bad9a0 [ 768x1280: 768,  3]
...

将显示窗口的尺寸设为1080×1920之后:

$ adb shell dumpsys SurfaceFlinger
...
+ Layer 0xb7d596b8 (com.android.phasebeam.PhaseBeamWallpaper)
  Region transparentRegion (this=0xb7d59818, count=1)
    [  0,   0,   0,   0]
  Region visibleRegion (this=0xb7d596c0, count=1)
    [  0,  50, 1080, 1824]
      layerStack=   0, z=    21000, pos=(0,0), size=(1080,1920), crop=(   0,  50,1080,1824), isOpaque=1, invalidate=0, alpha=0xff, flags=0x00000002, tr=[1.00, 0.00][0.00, 1.00]
      client=0xb7dbf270
      format= 2, activeBuffer=[1080x1920:1152,  3], queued-frames=0, mRefreshPending=0
            mTexName=10 mCurrentTexture=2
            mCurrentCrop=[0,0,0,0] mCurrentTransform=0
            mAbandoned=0
            -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[1080x1920], default-format=2, transform-hint=00, FIFO(0)={}
             [00:0xb7dd1fb0] state=FREE    , 0xb7dd0048 [1080x1920:1152,  3]
             [01:0xb7d5c2c8] state=FREE    , 0xb7d39ca8 [1080x1920:1152,  3]
            >[02:0xb7d1d578] state=ACQUIRED, 0xb7d5cb18 [1080x1920:1152,  3]
...

可以想象得到,系统把这个layer对应的窗口当成了一个1080p屏幕来布局和绘制了。
设置屏幕的dpi

$ adb shell wm density 320

Android 将实际屏幕尺寸和密度的范围 分为:

1.四种通用尺寸:小、正常、 大 和超大

2.六种通用的密度:

  • ldpi(低)~120dpi
  • mdpi(中)~160dpi
  • hdpi(高)~240dpi
  • xhdpi(超高)~320dpi
  • xxhdpi(超超高)~480dpi
  • xxxhdpi(超超超高)~640dpi


常用的dpi有160(mdpi), 240(hdpi), 320(xhdpi), 480(xxhdpi)。重置可用如下命令:

$ adb shell wm density reset

如何实现 ,以设置显示窗口尺寸为例(@android-5.1.1)
首先看一下wm命令如何通知WindowManagerService更新配置:
代码:frameworks/base/cmds/wm/src/com/android/commands/wm/Wm.java

public class Wm extends BaseCommand {
    ...
    public void onRun() throws Exception {
        mWm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
                        Context.WINDOW_SERVICE));
        if (mWm == null) {
            System.err.println(NO_SYSTEM_ERROR_CODE);
            throw new AndroidException("Can't connect to window     manager; is the system running?");
        }

        String op = nextArgRequired();

        if (op.equals("size")) {
            runDisplaySize();
        } else if (op.equals("density")) {
            runDisplayDensity();
        } else if (op.equals("overscan")) {
            runDisplayOverscan();
        } else {
            showError("Error: unknown command '" + op + "'");
            return;
        }
    }
    ...
    private void runDisplaySize() throws Exception {
        String size = nextArg();
        int w, h;
        if (size == null) {
            Point initialSize = new Point();
            Point baseSize = new Point();
            try {
                mWm.getInitialDisplaySize(Display.DEFAULT_DISPLAY, initialSize);
                mWm.getBaseDisplaySize(Display.DEFAULT_DISPLAY, baseSize);
                System.out.println("Physical size: " + initialSize.x + "x" + initialSize.y);
                if (!initialSize.equals(baseSize)) {
                    System.out.println("Override size: " + baseSize.x + "x" + baseSize.y);
                }
            } catch (RemoteException e) {
            }
            return;
        } else if ("reset".equals(size)) {
            w = h = -1;
        } else {
            int div = size.indexOf('x');
            if (div <= 0 || div >= (size.length()-1)) {
                System.err.println("Error: bad size " + size);
                return;
            }
            String wstr = size.substring(0, div);
            String hstr = size.substring(div+1);
            try {
                w = Integer.parseInt(wstr);
                h = Integer.parseInt(hstr);
            } catch (NumberFormatException e) {
                System.err.println("Error: bad number " + e);
                return;
            }
        }

        try {
            if (w >= 0 && h >= 0) {
                // TODO(multidisplay): For now Configuration only applies to main screen.
                mWm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h);
            } else {
                mWm.clearForcedDisplaySize(Display.DEFAULT_DISPLAY);
            }
        } catch (RemoteException e) {
        }
    }
    ...
}

先获取WindowManagerService再调用它的setForcedDisplaySize()方法。
代码:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    ...
    @Override
    public void setForcedDisplaySize(int displayId, int width, int height) {
        if (mContext.checkCallingOrSelfPermission(
                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
                PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Must hold permission " +
                        android.Manifest.permission.WRITE_SECURE_SETTINGS);
        }
        if (displayId != Display.DEFAULT_DISPLAY) {
            throw new IllegalArgumentException("Can only set the default display");
        }
        final long ident = Binder.clearCallingIdentity();
        try {
            synchronized(mWindowMap) {
                // Set some sort of reasonable bounds on the size of the display that we
                // will try to emulate.
                final int MIN_WIDTH = 200;
                final int MIN_HEIGHT = 200;
                final int MAX_SCALE = 2;
                final DisplayContent displayContent = getDisplayContentLocked(displayId);
                if (displayContent != null) {
                    width = Math.min(Math.max(width, MIN_WIDTH),
                            displayContent.mInitialDisplayWidth *   MAX_SCALE);
                    height = Math.min(Math.max(height, MIN_HEIGHT),
                            displayContent.mInitialDisplayHeight *  MAX_SCALE);
                    setForcedDisplaySizeLocked(displayContent, width, height);
                    Settings.Global.putString(mContext.getContentResolver(),
                            Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
                }
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }
    ...
    // displayContent must not be null
    private void setForcedDisplaySizeLocked(DisplayContent  displayContent, int width, int height) {
        Slog.i(TAG, "Using new display size: " + width + "x" + height);

        synchronized(displayContent.mDisplaySizeLock) {
            displayContent.mBaseDisplayWidth = width;
            displayContent.mBaseDisplayHeight = height;
        }
        reconfigureDisplayLocked(displayContent);
    }
    ...
    // displayContent must not be null
    private void reconfigureDisplayLocked(DisplayContent displayContent) {
        // TODO: Multidisplay: for now only use with default display.
        configureDisplayPolicyLocked(displayContent);
        displayContent.layoutNeeded = true;

        boolean configChanged = updateOrientationFromAppTokensLocked(false);
        mTempConfiguration.setToDefaults();
        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
        if (computeScreenConfigurationLocked(mTempConfiguration)) {
            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
                configChanged = true;
            }
        }

        if (configChanged) {
            mWaitingForConfig = true;
            startFreezingDisplayLocked(false, 0, 0);
            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
        }

        performLayoutAndPlaceSurfacesLocked();
    }
    ...
    }
    setForcedDisplaySize()->setForcedDisplaySizeLocked()->reconfigureDisplayLocked()->SEND_NEW_CONFIGURATION

这里可以看到可以设置的屏幕窗口最小为(200,200),最大小显示屏分辨率的两倍。
而WindowManagerService又是如何通知DisplayManagerService更新配置:

WindowsManagerService$H.handleMessage(SEND_NEW_CONFIGURATION)
->WindowManagerService.sendNewConfiguration()
->ActivityManagerService.updateConfiguration() x2
->WindowManagerService.setNewConfiguration()
->WindowManagerService.performLayoutAndPlaceSurfacesLocked()
->WindowManagerService.performLayoutAndPlaceSurfaceLockedLoop()
->WindowManagerService.performLayoutAndPlaceSurfaceLockedInner()
->DisplayManagerService$LocalService.performTraversalInTransactionFromWindowManager()
->DisplayManagerService.access$4200()
->DisplayManagerService.performTraversalInTransactionFromWindowManagerInternal()
->DisplayManagerService.performTraversalInTransactionLocked()
->DisplayManagerService.configureDisplayInTransactionLocked()
->LogicalDisplay.configureDisplayInTransactionLocked()

到这里就会去设置layer stack的尺寸和在屏幕上的位置:

final class LogicalDisplay {
    ...
    /**
     * Applies the layer stack and transformation to the given display device
     * so that it shows the contents of this logical display.
     *
     * We know that the given display device is only ever showing the contents of
     * a single logical display, so this method is expected to blow away all of its
     * transformation properties to make it happen regardless of what the
     * display device was previously showing.
     *
     * The caller must have an open Surface transaction.
     *
     * The display device may not be the primary display device, in the case
     * where the display is being mirrored.
     *
     * @param device The display device to modify.
     * @param isBlanked True if the device is being blanked.
     */
    public void configureDisplayInTransactionLocked(DisplayDevice device,
            boolean isBlanked) {
        final DisplayInfo displayInfo = getDisplayInfoLocked();
    final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();

        // Set the layer stack.
        device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack);

        // Set the refresh rate
        device.requestRefreshRateLocked(mRequestedRefreshRate);

        // Set the viewport.
        // This is the area of the logical display that we intend to show on the
        // display device.  For now, it is always the full size of the logical display.
        mTempLayerStackRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);

        // Set the orientation.
        // The orientation specifies how the physical coordinate system of the display
        // is rotated when the contents of the logical display are rendered.
        int orientation = Surface.ROTATION_0;
        if ((displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) {
            orientation = displayInfo.rotation;
        }

        // Apply the physical rotation of the display device itself.
        orientation = (orientation + displayDeviceInfo.rotation) % 4;

        // Set the frame.
        // The frame specifies the rotated physical coordinates into which the viewport
        // is mapped.  We need to take care to preserve the aspect ratio of the viewport.
    // Currently we maximize the area to fill the display, but we could try to be
        // more clever and match resolutions.
        boolean rotated = (orientation == Surface.ROTATION_90
                || orientation == Surface.ROTATION_270);
        int physWidth = rotated ? displayDeviceInfo.height : displayDeviceInfo.width;
        int physHeight = rotated ? displayDeviceInfo.width : displayDeviceInfo.height;

        // Determine whether the width or height is more constrained to be scaled.
        //    physWidth / displayInfo.logicalWidth    => letter box
        // or physHeight / displayInfo.logicalHeight  => pillar box
        //
        // We avoid a division (and possible floating point imprecision) here by
        // multiplying the fractions by the product of their denominators before
        // comparing them.
        int displayRectWidth, displayRectHeight;
        if (physWidth * displayInfo.logicalHeight
                < physHeight * displayInfo.logicalWidth) {
            // Letter box.
            displayRectWidth = physWidth;
            displayRectHeight = displayInfo.logicalHeight * physWidth / displayInfo.logicalWidth;
        } else {
            // Pillar box.
            displayRectWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight;
            displayRectHeight = physHeight;
        }
        int displayRectTop = (physHeight - displayRectHeight) / 2;
        int displayRectLeft = (physWidth - displayRectWidth) / 2;
        mTempDisplayRect.set(displayRectLeft, displayRectTop,
            displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);

        device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
    }
    ...
}

->DisplayDevice.setProjectionInTransactionLocked()
通知SurfaceFlinger:

abstract class DisplayDevice {
    ...
    /**
     * Sets the display projection while in a transaction.
     *
     * @param orientation defines the display's orientation
     * @param layerStackRect defines which area of the window manager coordinate
     *            space will be used
     * @param displayRect defines where on the display will layerStackRect be
     *            mapped to. displayRect is specified post-orientation, that is
     *            it uses the orientation seen by the end-user
     */
    public final void setProjectionInTransactionLocked(int orientation,
            Rect layerStackRect, Rect displayRect) {
        if (mCurrentOrientation != orientation
                || mCurrentLayerStackRect == null
                || !mCurrentLayerStackRect.equals(layerStackRect)
                || mCurrentDisplayRect == null
                || !mCurrentDisplayRect.equals(displayRect)) {
            mCurrentOrientation = orientation;

            if (mCurrentLayerStackRect == null) {
                mCurrentLayerStackRect = new Rect();
            }
            mCurrentLayerStackRect.set(layerStackRect);

            if (mCurrentDisplayRect == null) {
                mCurrentDisplayRect = new Rect();
            }
            mCurrentDisplayRect.set(displayRect);

            SurfaceControl.setDisplayProjection(mDisplayToken,
                    orientation, layerStackRect, displayRect);
        }
    }
    ...
}

最后,SurfaceFlinger就会跟据这些信息对Layer进行合成,显示在屏幕上。
代码:frameworks/native/services/surfaceflinger/DisplayDevice.cpp

void DisplayDevice::setProjection(int orientation,
        const Rect& newViewport, const Rect& newFrame) {
    Rect viewport(newViewport);
    Rect frame(newFrame);

    const int w = mDisplayWidth;
    const int h = mDisplayHeight;

    Transform R;
    DisplayDevice::orientationToTransfrom(orientation, w, h, &R);

    if (!frame.isValid()) {
        // the destination frame can be invalid if it has never been set,
        // in that case we assume the whole display frame.
        frame = Rect(w, h);
    }

    if (viewport.isEmpty()) {
        // viewport can be invalid if it has never been set, in that case
        // we assume the whole display size.
        // it's also invalid to have an empty viewport, so we handle that
        // case in the same way.
        viewport = Rect(w, h);
        if (R.getOrientation() & Transform::ROT_90) {
            // viewport is always specified in the logical orientation
            // of the display (ie: post-rotation).
            swap(viewport.right, viewport.bottom);
        }
    }

    dirtyRegion.set(getBounds());

    Transform TL, TP, S;
    float src_width  = viewport.width();
    float src_height = viewport.height();
    float dst_width  = frame.width();
    float dst_height = frame.height();
    if (src_width != dst_width || src_height != dst_height) {
        float sx = dst_width  / src_width;
        float sy = dst_height / src_height;
        S.set(sx, 0, 0, sy);
    }

    float src_x = viewport.left;
    float src_y = viewport.top;
    float dst_x = frame.left;
    float dst_y = frame.top;
    TL.set(-src_x, -src_y);
    TP.set(dst_x, dst_y);

    // The viewport and frame are both in the logical orientation.
    // Apply the logical translation, scale to physical size, apply the
// physical translation and finally rotate to the physical orientation.
    mGlobalTransform = R * TP * S * TL;
    const uint8_t type = mGlobalTransform.getType();
    mNeedsFiltering = (!mGlobalTransform.preserveRects() ||
            (type >= Transform::SCALE));
    mScissor = mGlobalTransform.transform(viewport);
    if (mScissor.isEmpty()) {
        mScissor = getBounds();
    }
    mOrientation = orientation;
    mViewport = viewport;
    mFrame = frame;
}

aapt命令获取apk详细信息(包名、版本号、版本名称、兼容api级别、启动Activity等)

  1. 找到sdk的根目录,然后找到build-tools文件夹,然后会看到一些build-tools的版本号,随便点开一个,就可以看到aapt


  2. 获取apk的详细信息

    aapt dump badging app-debug.apk



你可能感兴趣的:(adb命令实现一些有趣的功能)