Utilizing the Android Open Source Project to Support Controllers for - - PowerPoint PPT Presentation

utilizing the android open source project to support
SMART_READER_LITE
LIVE PREVIEW

Utilizing the Android Open Source Project to Support Controllers for - - PowerPoint PPT Presentation

Utilizing the Android Open Source Project to Support Controllers for Single-Use Devices X-Ray Guns! Pew Pew! Watson Project Overview Watson Project Overview ALLOY B-3 Ni: 53.7% Mo: 29.3% Watson Architecture X-Ray Source External Battery


slide-1
SLIDE 1

Utilizing the Android Open Source Project to Support Controllers for Single-Use Devices

X-Ray Guns! Pew Pew!

slide-2
SLIDE 2

Watson Project Overview

slide-3
SLIDE 3

Watson Project Overview

ALLOY B-3 Ni: 53.7% Mo: 29.3%

slide-4
SLIDE 4

Watson Controller Board LEDs Camera Trigger X-Ray Detector

Watson Architecture

X-Ray Source USB Peripherals External Battery Watson Controller Board

slide-5
SLIDE 5

What we’re covering

slide-6
SLIDE 6

What we’re covering

  • AOSP Customizations
slide-7
SLIDE 7

What we’re covering

  • AOSP Customizations
  • App-specific Features
slide-8
SLIDE 8

What we’re covering

  • AOSP Customizations
  • App-specific Features
  • Problems that we overcame
slide-9
SLIDE 9

AOSP Customization

slide-10
SLIDE 10

AOSP Customization

  • Pre-5.x Kiosk Mode
slide-11
SLIDE 11

AOSP Customization

  • Pre-5.x Kiosk Mode
  • Altering the status bar
slide-12
SLIDE 12

AOSP Customization

  • Pre-5.x Kiosk Mode
  • Altering the status bar
  • Using the Android settings GUI in our application
slide-13
SLIDE 13

AOSP Customizations

Where to get it https://source.android.com/source/ Basic file structure frameworks/base - Android-specific code packages/apps - Where to put your app / apk device/ [lge/hammerhead] - hw-specific config files

slide-14
SLIDE 14

AOSP Customizations - Build specifics

export USE_CCACHE=1 export LANG=C export PATH=$PATH:/usr/lib/jvm/java-1.7.0-openjdk-amd64/bin #Set an awesome (and transient) output directory export OUT_DIR_COMMON_BASE=/home/volatile/bfriedberg . build/envsetup.sh lunch <pick your release, I used ‘aosp_hammerhead-userdebug’> make [-j30]

slide-15
SLIDE 15

Kiosk mode

slide-16
SLIDE 16

Kiosk mode

There are many options

  • Car mode
  • Launcher replacement
  • Pinned Activities (5.0+)
  • Sealed Mode (5.0+)

http://sdgsystems.com/blog/implementing-kiosk-mode-android-part-1/

slide-17
SLIDE 17

Kiosk mode

Android navigation paradigms get in the way

  • Home button
  • Back button
  • Notification Bar
slide-18
SLIDE 18

Kiosk mode

Our approach

  • Launcher Removal / Replacement
  • Fake Hardware Keys (to remove soft buttons)
  • Override the notification bar
slide-19
SLIDE 19

Kiosk mode - Launcher Replacement

Add your app to packages/apps with this Android.mk file:

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := <package_name> LOCAL_MODULE_CLASS := APPS LOCAL_MODULE_TAGS := optional LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) LOCAL_CERTIFICATE := platform LOCAL_OVERRIDES_PACKAGES := Launcher2 Launcher3 #this is optional LOCAL_SRC_FILES := <apk_name>.apk LOCAL_MODULE_OWNER := system include $(BUILD_PREBUILT)

slide-20
SLIDE 20

Kiosk mode - Launcher Replacement

In device/lge/hammerhead/aosp_hammerhead.mk: Delete Launcher3 and add the name of your app to the PRODUCT_PACKAGES collection

slide-21
SLIDE 21

Kiosk mode - Launcher Replacement

In your App’s AndroidManifest.xml:

<activity android:name=".ui.SplashActivity" android:screenOrientation="portrait" android:windowSoftInputMode="stateAlwaysVisible" > <intent-filter android:priority="1000" > <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.HOME" /> <category android:name="RUN_AT_BOOT" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>

slide-22
SLIDE 22

Kiosk mode - Fake Hardware Keys

In device/lge/hammerhead/aosp_hammerhead.mk

# Disable the navigation bar PRODUCT_PROPERTY_OVERRIDES += \ qemu.hw.mainkeys=1

slide-23
SLIDE 23

Kiosk mode - Notification Bar

public void disableNotificationBarShade() throws ClassNotFoundException { Object object = this.getSystemService("statusbar"); Class<?> statusBarManager; statusBarManager = Class.forName("android.app.StatusBarManager"); Method[] method = statusBarManager.getMethods(); Field fld[] = statusBarManager.getDeclaredFields(); Class name = object.getClass(); Field field = statusBarManager.getDeclaredField("DISABLE_EXPAND"); Method disable = statusBarManager.getMethod("disable", new Class[] { int.class }); disable.setAccessible(true); field.setAccessible(true); disable.invoke(object,Integer.valueOf(field.getInt(statusBarManager)));

}

slide-24
SLIDE 24

Altering the status bar

slide-25
SLIDE 25

Altering the status bar

  • Battery level
slide-26
SLIDE 26

Altering the status bar

  • Battery level
  • Add labels
slide-27
SLIDE 27

Altering the status bar

  • Battery level
  • Add labels
  • Change Icons
slide-28
SLIDE 28

Altering the status bar - Battery level

frameworks/base/packages/SystemUI/src/com/android/systemui/ BatteryMeterView.java: public class BatteryMeterView extends View implements DemoMode {

… //public static final String mBatteryIntent = Intent.ACTION_BATTERY_CHANGED; public static final String mBatteryIntent = "<package>.action.battery_changed"; … // if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { if (action.equals(mBatteryIntent)) { <etc…>

In your app, issue the intent it with:

intent.putExtra(BatteryManager.EXTRA_LEVEL, level); //0-100 intent.putExtra(BatteryManager.EXTRA_PLUGGED, chargingValue); //[0,1] sendBroadcastAsUser(intent, new UserHandle(Parcel.obtain()));

slide-29
SLIDE 29

Altering the status bar - Battery level

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/polic y/BatteryController.java -- Change the constructor to take a custom intent action frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone /PhoneStatusBar.java -- Construct the mBatteryController with the custom intent

slide-30
SLIDE 30

Altering the status bar - Adding labels

Status bar layout is in

frameworks/base/packages/SystemUI/res/layout/status_bar.xml

Add a new TextView (or whatever) and then use a custom intent to manipulate it in

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone /PhoneStatusBar.java

slide-31
SLIDE 31

Altering the status bar - Change Icons

/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/poli cy/NetworkController.java -- holds some code to remove cell signal icons: ... else { // normal mobile data cluster.setMobileDataIndicators(

  • mHasMobileDataFeature,
  • mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,

+ false, + 0, ...

slide-32
SLIDE 32

Reusing Android Settings

slide-33
SLIDE 33

Reusing Android Settings

  • Wi-Fi
slide-34
SLIDE 34

Reusing Android Settings

  • Wi-Fi
  • Date / Time
slide-35
SLIDE 35

packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java

  • nResume() {

... activity.getActionBar().setDisplayHomeAsUpEnabled(true); } public boolean onOptionsItemSelected(MenuItem item) { if(item.getTitle().equals("Wi\u2011Fi")) { Log.d(TAG, "Hit the 'back' button, finishing the settings activity"); finish(); return true; }

In your application: Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS); startActivity(intent);

Reusing Android Settings - Wi-Fi

slide-36
SLIDE 36

Reusing Android Settings - Date / Time

packages/apps/Settings/src/com/android/settings/DateTimeSettings.java

  • nResume() {

... activity.getActionBar().setDisplayHomeAsUpEnabled(true); } public boolean onOptionsItemSelected(MenuItem item) { if(item.getTitle().startsWith("Date")) { Log.d(TAG, "Hit the 'back' button, finishing the settings activity"); finish(); return true; }

In your application: Intent intent = new Intent(Settings.ACTION_DATE_SETTINGS); startActivity(intent);

slide-37
SLIDE 37

App-Specific Features

slide-38
SLIDE 38

App-Specific Features

  • USB hardware interaction
slide-39
SLIDE 39

App-Specific Features

  • USB hardware interaction
  • Supporting an external video source w/ live preview and

capture

slide-40
SLIDE 40

App-Specific Features

  • USB hardware interaction
  • Remote Updates w/out the Google Play Store
slide-41
SLIDE 41

USB hardware interaction

  • USB Serial library
  • Bound services
  • Messengers as callbacks

Application logic Service holding a persistent USB Connection Binder Commands Messenger Responses USB Device

slide-42
SLIDE 42

https://github.com/mik3y/usb-serial-for-android A FANTASTIC resource for anyone dealing with Android USB implementations.

USB hardware interaction - USB Serial library

slide-43
SLIDE 43

class WatsonUsbDevice { private UsbDeviceConnection usbConnection; private android.hardware.usb.UsbDevice usbDevice; private UsbSerialPort port; public CustomUsbDevice(UsbDevice usbDevice, UsbDeviceConnection connection) { this.usbDevice = usbDevice; this.usbConnection = connection; UsbInterface intf = usbDevice.getInterface(0); usbConnection.claimInterface(intf, true); UsbSerialDriver driver = UsbSerialProber.getDefaultProber().probeDevice(usbDevice); for (UsbSerialPort port : driver.getPorts()) { this.port = port; break; } try { port.open(connection); } catch (Exception e) { log.error(Logs.DEV_DEBUG,"Exception in Device():", e); } } ...

USB hardware interaction - USB

slide-44
SLIDE 44

USB hardware interaction - Bound services

public class WatsonService extends Service { ... public class WatsonServiceBinder extends Binder { public WatsonServiceBinder() { super(); binderInstance = this; } public WatsonService getService() { return WatsonService.this; } public void enableSource(boolean enable, int seconds) { if(watsonUsbDevice != null) { watsonUsbDevice.enableSourcePower(enable, seconds); } } } }

slide-45
SLIDE 45

private ServiceConnection mWatsonConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mWatsonServiceBinder = (WatsonService.WatsonServiceBinder) service; watsonBound = true; } @Override public void onServiceDisconnected(ComponentName name) { mWatsonServiceBinder = null; watsonBound = false; } }; Intent intent = new Intent(context, WatsonService.class); mContext.bindService(intent, mWatsonConnection, Context.BIND_AUTO_CREATE); mWatsonServiceBinder.enableSource(true, 10);

USB hardware interaction - Bound services

slide-46
SLIDE 46

USB hardware interaction - Messengers

//Define the messenger and how to handle incoming messages private Messenger mWatsonMessenger = new Messenger(new Handler() { @Override public void handleMessage(Message msg) { //filter out chatty battery messages if(msg.what != WatsonMessages.WATSON_MESSAGE_RESPONSE_BATTERY_GAUGE) { log.debug(Logs.EVENT, "got message " + msg.what); } //HANDLE THE MESSAGE based on msg.what } }

slide-47
SLIDE 47

USB hardware interaction - Messengers

private ServiceConnection mWatsonConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mWatsonServiceBinder = (WatsonService.WatsonServiceBinder) service; mWatsonServiceBinder.registerMessenger(mWatsonMessenger); watsonBound = true; } @Override public void onServiceDisconnected(ComponentName name) { mWatsonServiceBinder.unregisterMessenger(mWatsonMessenger); mWatsonServiceBinder = null; watsonBound = false; } }; Intent intent = new Intent(context, WatsonService.class); mContext.bindService(intent, mWatsonConnection, Context.BIND_AUTO_CREATE);

slide-48
SLIDE 48

USB hardware interaction - Messengers

WatsonService.java: //In the service, register the messenger w/ the usb device public void registerMessenger(Messenger messenger) { if(watsonUsbDevice != null) { watsonUsbDevice.registerMessenger(messenger); } } WatsonUSBDevice.java: public void registerMessenger(Messenger clientMessenger) { if(this.mClientMessengers == null) { this.mClientMessengers = new ArrayList<Messenger>(); } this.mClientMessengers.add(clientMessenger); }

slide-49
SLIDE 49

USB hardware interaction - Messengers

WatsonUSBDevice.java Bundle dataBundle = new Bundle(); WatsonPacket packet; if(bytes[1] == WatsonPacketTypes.COMMAND_RESPONSE_OPERATING_STATUS_HEADER[1]) { packet = new WatsonOperatingStatusPacket(bytes); } else if (.... for (int i=mClientMessengers.size()-1; i>=0; i--) { Messenger mClientMessenger = mClientMessengers.get(i); Message dataMessage = packet.getMessageType(); if(dataMessage != null) { dataBundle.putParcelable(WatsonMessages.KEY_DATA_BYTES, packet); dataMessage.setData(dataBundle); if(mClientMessenger != null) { mClientMessenger.send(dataMessage); } } }

slide-50
SLIDE 50

USB hardware interaction

For a more detailed example of services and messengers, check out our blog post:

http://sdgsystems.com/blog/using-android-ndk-android-studio-part-3/

slide-51
SLIDE 51

Remote Updates w/out the Google Play Store

slide-52
SLIDE 52

Remote Updates w/out the Google Play Store

  • Update Service
slide-53
SLIDE 53

Remote Updates w/out the Google Play Store

  • Update Service
  • Downloading / installing APKs programmatically
slide-54
SLIDE 54

Remote Updates w/out the Google Play Store

  • Update Service
  • Downloading / installing APKs programmatically
  • Implementing workflow deployment models
slide-55
SLIDE 55

Remote Updates w/out the Google Play Store - Update Service

slide-56
SLIDE 56

Remote Updates w/out the Google Play Store - Update Service

  • Periodic background update service checking a stored

URL

slide-57
SLIDE 57

Remote Updates w/out the Google Play Store - Update Service

  • Periodic background update service checking a stored

URL

  • Check / Verify current version
slide-58
SLIDE 58

Remote Updates w/out the Google Play Store - Update Service

  • Periodic background update service checking a stored

URL

  • Check / Verify current version
  • Prompt user for manual updates
slide-59
SLIDE 59

Remote Updates w/out the Google Play Store - Installing APKs

final UserManager um = (UserManager) _context.getSystemService(Context.USER_SERVICE); Settings.Global.putInt(_context.getContentResolver(), Settings.Global. INSTALL_NON_MARKET_APPS, 1); //inside an asyncTask: … Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(new File("/mnt/sdcard/Download/watsonupdate.apk")), "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); _context.startActivity(intent);

slide-60
SLIDE 60

Remote Updates w/out the Google Play Store - Deployment models

Using this update architecture, we were able to handle build deployment and promotion by targeting different update URLs.

slide-61
SLIDE 61

Problems that we didn’t expect

slide-62
SLIDE 62

Problems that we didn’t expect

  • Debugging on an enclosed unit
slide-63
SLIDE 63

Problems that we didn’t expect

  • Debugging on an enclosed unit
  • Android Studio support for statically linking pre-built

NDK libraries

slide-64
SLIDE 64

Problems that we didn’t expect

  • Debugging on an enclosed unit
  • Android Studio support for statically linking pre-built

NDK libraries

  • Handling USB charging while in host mode
slide-65
SLIDE 65

Debugging an enclosed unit

slide-66
SLIDE 66

Debugging an enclosed unit - ADB

  • ver Wi-Fi

The following will put the device’s ADB connection in tcpip mode:

# adb tcpip 5555 restarting in TCP mode port: 5555 # adb connect 192.168.2.106 connected to 192.168.2.106:5555

Problem: We need a USB connection to do set this up!

slide-67
SLIDE 67

Debugging an enclosed unit - Setprop solution

  • n property:watson.adb.tcpip=1

stop adbd setprop service.adb.tcp.port 5555 start adbd

  • n property:watson.adb.tcpip=0

stop adbd setprop service.adb.tcp.port -1 start adbd

Without a rooted device, you cannot get user rights to issue setprop commands that init will be able to see.

slide-68
SLIDE 68

Debugging an enclosed unit - Default properties

device/lge/hammerhead/aosp_hammerhead.mk:

PRODUCT_PROPERTY_OVERRIDES += \ qemu.hw.mainkeys=1 \ watson.adb.tcpip=1

slide-69
SLIDE 69

Android Studio support for statically linking NDK libraries

slide-70
SLIDE 70

Android Studio support for statically linking NDK libraries

PREBUILT_STATIC_LIBRARY not supported

slide-71
SLIDE 71

build.gradle changes:

Android Studio support for statically linking NDK libraries

slide-72
SLIDE 72

build.gradle changes:

  • Override the default JNI compilation

Android Studio support for statically linking NDK libraries

slide-73
SLIDE 73

build.gradle changes:

  • Override the default JNI compilation
  • Create a task to fire at compile time to manually compile

JNI

Android Studio support for statically linking NDK libraries

slide-74
SLIDE 74

build.gradle changes:

  • Override the default JNI compilation
  • Create a task to fire at compile time to manually compile

JNI

  • Add a properties file for ndk build path

Android Studio support for statically linking NDK libraries

slide-75
SLIDE 75

apply from: '../properties.gradle' defaultConfig { … sourceSets.main { jniLibs.srcDir 'src/main/libs' jni.srcDirs = []; } } … tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn ndkBuild } task ndkBuild(type: Exec) { commandLine ndk_build_path, '-C', file('src/main/jni').absolutePath }

Android Studio support for statically linking NDK libraries

slide-76
SLIDE 76

properties.gradle: project.ext.ndk_build_path = "/home/bfriedberg/android-ndk/android-ndk-r10/ndk-build" src/main/jni/Android.mk: … include $(CLEAR_VARS) LOCAL_MODULE := libFP32 LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libFP32.a include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libMTFxpro LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libMTFxpro.a include $(PREBUILT_STATIC_LIBRARY) …

Android Studio support for statically linking NDK libraries

slide-77
SLIDE 77

Android Studio support for statically linking NDK libraries

For a more detailed example of linking in your ndk project:

http://sdgsystems.com/blog/using-android-ndk-android-studio-part-1/

slide-78
SLIDE 78

Handling USB charging while in host mode

  • Hostmode charging is prevented by default
  • You won’t get notification
  • OTG pin
slide-79
SLIDE 79

How did you handle X?

Questions?