Android 收银机开发笔记

Summer Wind

前言:记录下自己在收银机开发过程中的一些心得笔记,此博客长期更新。

00 收银机开发和普通安卓手机应用开发的区别

个人觉得,最大的区别就是,屏幕空间变大了,一屏之内可展示的内容变多了。其实不仅仅是屏幕空间变大了,也由原来的习惯看竖屏到习惯看横屏了。另外需要做的适配工作也简单很多,因为收银机屏幕分辨率和屏幕大小都差不多,几乎不需要做特殊的适配,而且你甚至可以更改屏幕密度!下面会说到。

还有一点就是,不再需要担心应用保活的问题了,因为基本上安装到商家的收银机上之后,我们的应用就是主角,所以可供我们发挥的空间就大了。另外诸如开机自启、系统敏感权限等,这些都不是事儿~

虽然少了很多限制,但还是想说,安全对一款收银机应用来说还是非常重要的,比如怎样保证应用的数据安全以及网络安全,这些都是目前还没来得及做、未来需要完善的。

01 应用全屏

PART 1

一般来说,我们的收银机应用大多数时候都应该占满屏幕,所以需要用到全屏模式:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:windowAnimationStyle">@style/notAnimation</item>
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowContentOverlay">@null</item>
</style>

可以看到我们使用了 Theme.AppCompat.Light.NoActionBar 作为父主题,然后覆盖了 android:windowFullscreenandroid:windowContentOverlay 属性,前者用于隐藏状态栏,后者用于消除包裹应用 content 的 drawable(通常是标题下的阴影),参考 windowContentOverlay

PART 2

当然,这些只是最基本的,我们还需要处理 activity 配置发生改变的情况,在 activity 下添加:

android:configChanges="orientation|screenSize|keyboardHidden"

这样,我们就告诉系统当 activity 屏幕方向或者键盘可见性发生变化后不要退出重启 activity,因为收银机应用几乎所有 activity 屏幕方向都应该是水平的。

另外关于键盘,还需要在 activity 中加上 android:windowSoftInputMode="stateHidden|adjustPan" 属性,stateHidden 表明当用户初次进入 activity 的时候,键盘不会显示出来(一般只有在登录界面才会需要键盘一开始就显示),而 adjustPan 则会在键盘显示出来的时候自动调整 UI 内容,让用户始终可以看到他们输入的内容而不是被键盘覆盖掉。

所以 AndroidManifest 中我们的 activity 大多数是这样配置的:

<activity
    android:configChanges="orientation|keyboardHidden|screenSize"
    android:screenOrientation="landscape"
    android:windowSoftInputMode="stateHidden|adjustPan" />

具体参数介绍请看 <activity>

PART 3

这些就够了吗?当然不是!通常,我们还需要在我们的 BaseActivity 中做如下配置:

//开启全屏
final int fullScreenFlags = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
        | View.SYSTEM_UI_FLAG_FULLSCREEN //hide statusBar
        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION //hide navigationBar
        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;

final Window window = getWindow();
window.getDecorView().setSystemUiVisibility(fullScreenFlags);
window.getDecorView().setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
    @Override
    public void onSystemUiVisibilityChange(int visibility) {
        window.getDecorView().setSystemUiVisibility(fullScreenFlags);
    }
});

可以看到我们给 DecorView 设置了一些 Visibility 的 Flag, 首先是隐藏状态栏和导航栏,然后是 View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 用于沉浸模式,也就是使状态栏变得半透明,同时接受屏幕边缘的滑动事件(通常这类事件是由系统处理掉的)。文档上是这么写的:

While in sticky immersive mode, if the user swipes from an edge with a system bar, system bars appear but they're semi-transparent, and the touch gesture is passed to your app so it app can also respond to the gesture.

然后是 View.SYSTEM_UI_FLAG_LAYOUT_STABLE 用于保证你的布局全屏,不会因为系统栏的显示而重新调整大小。具体请参考文档:Enable fullscreen mode

PART 4

除此之外,我们还应该考虑到一些特殊情况,比如显示 dialog 或者用户输入的情况下,这些时候导航栏都会显示出来,所以通常我们还会写这么一个方法:

public void enterFullScreen(Window window) {
    window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
    int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
        | View.SYSTEM_UI_FLAG_FULLSCREEN;
    window.getDecorView().setSystemUiVisibility(uiOptions);
}

然后在显示 dialog 或者其他一些有可能触发导航栏显示的地方调用下这个方法,这样就能保证始终全屏啦。另外对于监听键盘输入,推荐一个三方库:KeyboardVisibilityEvent,使用起来非常方便,只要在 activity 初始化的地方调用:

KeyboardVisibilityEvent.setEventListener(this,
    new KeyboardVisibilityEventListener() {
        @Override
        public void onVisibilityChanged(boolean isOpen) {
            UIHelper.create().enterFullScreen(getWindow());
        }
});

这样当用户使用键盘输入的时候,我们可以保证始终全屏显示。

最后,也许有人会有疑问,如果我们的应用开机自启,而且始终全屏,那不是无法回到桌面了吗?其实不用担心,我们可以自己设置一个按钮,提供回到桌面的功能,比如当用户点击右下角显示当前时间的地方。是不是听起来有点熟悉?没错,就是受到了 windows 的启发~ ʘ‿ʘ

02 修改收银机主屏幕密度

PART 1

首先说明下,这种方式只针对使用瑞芯芯片的收银机才有效,可以用以下命令检查是否是支持修改:

adb shell cat /system/build.prop | grep ro.sf.lcd_density
# or
adb shell getprop ro.sf.lcd_density

如果存在该属性则证明可以修改。下面是步骤(过时,参考 PART 3):

  1. /system/build.prop 文件拉到本地,使用 adb 命令:
adb pull /system/build.prop ./
  1. 打开 build.prop 文件,找到 ro.sf.lcd_density 属性,这个属性就是用来指定屏幕密度的,直接修改成我们想要的密度就可以了,默认是 160,我们可以修改为 240。个人觉得,对于一般收银机来说,这是看着最舒服的:
# set default lcd density to Rockchip tablet
ro.sf.lcd_density=240
  1. 将修改完毕后的文件覆盖掉原文件,当然首先要将 /system 挂载为可读写再覆盖:
adb root
adb shell mount -o rw,remount /system
adb push build.prop /system/
  1. 最后不要忘记修改 /system 为只读:
adb shell mount -o ro,remount /system
adb shell reboot

最后,当机子重启完毕,新的屏幕密度就已经起作用了。

PART 2

当然,上面这些步骤对于安卓开发来说没难度,但是对于运维来说,其实还是挺麻烦的,所以写了个 batch 脚本(运维用Windows -_-||),只要用数据线连接上收银机,双击运行下就ok了,我是不是很棒~

Github 地址:ChangeDensity-win-batch

PART 3

其实修改屏幕分辨率还有一个更简便的方法,那就是通过 adb 命令中的 Window Manager,一行命令就可以搞定:

adb shell wm density [reset|DENSITY] 

参数中 reset 表示恢复默认值,DENSITY 就是你想要修改成的屏幕密度,是不是异常简单?而且这种修改方式是立即生效的,和之前的方法一比简直不要太方便。同样只要检查 ro.sf.lcd_density 参数是否存在就可以了。另外,wm 全部命令如下:

usage: wm [subcommand] [options]
       wm size [reset|WxH|WdpxHdp]
       wm density [reset|DENSITY]
       wm overscan [reset|LEFT,TOP,RIGHT,BOTTOM]
       wm scaling [off|auto]
       wm screen-capture [userId] [true|false]

wm size: return or override display size.
         width and height in pixels unless suffixed with 'dp'.

wm density: override display density.

wm overscan: set overscan area for display.

wm scaling: set display scaling mode.

wm screen-capture: enable/disable screen capture.

wm dismiss-keyguard: dismiss the keyguard, prompting the user for auth if necessary.

wm surface-trace: log surface commands to stdout in a binary format.

可以看到屏幕分辨率也是可以直接修改的:

adb shell wm size [reset|WxH|WdpxHdp]

新技能 GET! (•̀ᴗ•́)و ̑̑


喜欢我的文章就用你最喜欢的手指点个赞吧~ (づ ̄3 ̄)づ╭❤~

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 138,275评论 20 591
  • 1回放我在事件当中是什么样的情绪? 情绪: 事件:今天去开家长会,听老师说他们班这次文艺会员,很多同学都展示了自己...
    胡傲宣阅读 31评论 0 0
  • 这学期学习的一个新课程是产品摄影,因为之前学习的一直是拍摄的是商业人像,所以对产品摄影这方面比较陌生。 老师在...
    鱼三秒阅读 372评论 2 7
  • 你们好!我第一次写小说、中学毕业并没有什么文采,这篇小说我不是要演绎些什么。我只是想把我这四年的经历和爱情故事分享...
    感博主阅读 41评论 0 0
  • 高一 高一下学期刚开学。 我总盯着教室外的花坛里那株正盛开的绿色梅花,秃秃的枝桠和略显浓密的花。枝很累吧?托着花朵...
    温心一阅读 86评论 0 0