下载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等)
-
找到sdk的根目录,然后找到build-tools文件夹,然后会看到一些build-tools的版本号,随便点开一个,就可以看到aapt
-
获取apk的详细信息
aapt dump badging app-debug.apk