Getting Started with Android N

5 things that will change, break and help your app




Marvin Ramin


Chapter 0:

The basics

Setup time!


The tools you need will need:

  • Android Studio 2.1
  • Android N Preview SDK
  • API Documentation
  • JDK 8
  • build.gradle

buildscript {
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.0-<some alpha/beta version here>'
    }
}

android {
    compileSdkVersion 'android-N'
    buildToolsVersion "24.0.0 rc1"

    defaultConfig {
        minSdkVersion 'N'
        targetSdkVersion 'N'
    }
}
					

Prepare your device


Works with all Nexus deivces > Nexus 6

RIP Nexus 5

Chapter 1:

The UI changes

Notifications

Quick Reply Notifications

  • RemoteInput API
  • Same as Android Wear

Quick Reply Notifications


RemoteInput remoteInput = new RemoteInput.Builder(RESULT_KEY_TEXT_REPLY)
        .setLabel("Reply")
        .build();

PendingIntent pendingIntent =
	PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0);

NotificationCompat.Action action =
        new NotificationCompat.Action.Builder(R.mipmap.ic_launcher, "Reply", pendingIntent)
                .addRemoteInput(remoteInput)
                .build();

NotificationCompat.Builder builder = baseNotification(context, "Quick reply", "You can reply to this...")
        .addAction(action);
				

Quick Reply Notifications


RemoteInput remoteInput = new RemoteInput.Builder(RESULT_KEY_TEXT_REPLY)
        .setLabel("Reply")
        .build();

PendingIntent pendingIntent =
	PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0);

NotificationCompat.Action action =
        new NotificationCompat.Action.Builder(R.mipmap.ic_launcher, "Reply", pendingIntent)
                .addRemoteInput(remoteInput)
                .build();

NotificationCompat.Builder builder = baseNotification(context, "Quick reply", "Title")
        .addAction(action);
				

Quick Reply Notifications


RemoteInput remoteInput = new RemoteInput.Builder(RESULT_KEY_TEXT_REPLY)
        .setLabel("Reply")
        .build();

PendingIntent pendingIntent =
	PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0);

NotificationCompat.Action action =
        new NotificationCompat.Action.Builder(R.mipmap.ic_launcher, "Reply", pendingIntent)
                .addRemoteInput(remoteInput)
                .build();

NotificationCompat.Builder builder = baseNotification(context, "Quick reply", "Title")
        .addAction(action);
				

Quick Reply Notifications


RemoteInput remoteInput = new RemoteInput.Builder(RESULT_KEY_TEXT_REPLY)
	.setLabel("Reply")
	.build();

PendingIntent pendingIntent =
	PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0);

NotificationCompat.Action action =
        new NotificationCompat.Action.Builder(R.mipmap.ic_launcher, "Reply", pendingIntent)
                .addRemoteInput(remoteInput)
                .build();

NotificationCompat.Builder builder = baseNotification(context, "Quick reply", "Title")
	.addAction(action);
				

Quick Reply Notifications


RemoteInput remoteInput = new RemoteInput.Builder(RESULT_KEY_TEXT_REPLY)
        .setLabel("Reply")
        .build();

PendingIntent pendingIntent =
	PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0);

NotificationCompat.Action action =
        new NotificationCompat.Action.Builder(R.mipmap.ic_launcher, "Reply", pendingIntent)
                .addRemoteInput(remoteInput)
                .build();

NotificationCompat.Builder builder = baseNotification(context, "Quick reply", "Title")
        .addAction(action);
				

Handling the Remote Input


Bundle bundle = RemoteInput.getResultsFromIntent(getIntent());
if (bundle == null) {
	return;
}

String replyText = bundle.getString(RESULT_KEY_TEXT_REPLY);
// Do something with the reply text

// You have to remove the notification once you're finished processing it
NotificationManager.removeReplyNotification(this);
				

Handling the Remote Input


Bundle bundle = RemoteInput.getResultsFromIntent(getIntent());
if (bundle == null) {
	return;
}

String replyText = bundle.getString(RESULT_KEY_TEXT_REPLY);
// Do something with the reply text

// You have to remove the notification once you're finished processing it
NotificationManager.removeReplyNotification(this);
				

Handling the Remote Input


Bundle bundle = RemoteInput.getResultsFromIntent(getIntent());
if (bundle == null) {
	return;
}

String replyText = bundle.getString(RESULT_KEY_TEXT_REPLY);
// Do something with the reply text

// You have to remove the notification once you're finished processing it
NotificationManager.removeReplyNotification(this);
				

Grouping Notifications

.setGroup(ID)

Create summary notification

.setGroupSummary(true)

Quick Settings

TileService

onTileAdded()

onTileRemoved()

onStartListening()

onStopListening()

onClick()

TileService

AndroidManifest.xml


<service
    android:name=".QuickSettingsTileService"
    android:label="N Playground"
    android:icon="@drawable/wave"
    android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
    <intent-filter>
        <action android:name="android.service.quicksettings.action.QS_TILE" />
    </intent-filter>
</service>
				

TileService

AndroidManifest.xml


<service
    android:name=".QuickSettingsTileService"
    android:label="N Playground"
    android:icon="@drawable/wave"
    android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
    <intent-filter>
        <action android:name="android.service.quicksettings.action.QS_TILE" />
    </intent-filter>
</service>
				

TileService

AndroidManifest.xml


<service
    android:name=".QuickSettingsTileService"
    android:label="N Playground"
    android:icon="@drawable/wave"
    android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
    <intent-filter>
        <action android:name="android.service.quicksettings.action.QS_TILE" />
    </intent-filter>
</service>
				

Shortcuts

Quick actions on Launcher icons

Can be added/removed dynamically

Accessed with "a gesture"

Possibly Force Touch?

Shortcuts

Chapter 2:

The multiple windows

Multi Window

Split-Screen mode

Picture in Picture

Freeform mode

Picture in Picture

Picture in Picture

Freeform

Multi Window

Be careful with orientation

Be careful with the lifecycle

Activity can still be visible in onPause()

Fixed orientation disables multi-window

Multi Window


			android:resizeableActivity=["true" | "false"]
					

			android:supportsPictureInPicture=["true" | "false"]
						

<activity android:name=".MyActivity">
	<layout
			android:defaultHeight="500dp"
			android:defaultWidth="600dp"
			android:gravity="top|end"
			android:minimalHeight="450dp"
			android:minimalWidth="300dp" />
</activity>
							

Multi Window

Intent.FLAG_ACTIVITY_LAUNCH_TO_ADJACENT

Drag and Drop

Helper methods and callbacks for mode changes

Chapter 3:

The developer toolchain

Java 8

Java 8 (kind of)

Java 8 Language Features with N

Lambdas

Default interface methods

Reflection APIs

java.util.function

java.util.stream

Java 8 Language Features below N

Lambdas

Default interface methods

Reflection APIs

java.util.function

java.util.stream

Jack & Jill


android {
  ...
  defaultConfig {
    ...
    jackOptions {
      enabled true
    }
  }
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}
					

Jack & Jill


android {
  ...
  defaultConfig {
    ...
    jackOptions {
      enabled true
    }
  }
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}
					

Jack & Jill


android {
  ...
  defaultConfig {
    ...
    jackOptions {
      enabled true
    }
  }
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}
					

Jack & Jill

Slightly slower than javac (currently)

Breaks Annotation Processing (currently)

No Instant Run (currently)

Breaks Kotlin (currently)

source.android.com

Chapter 4:

The small changes

X509TrustManager

Network Security Configuration

Network Security Configuration


<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config>
      <domain includeSubdomains="true">example.com</domain>
      <trust-anchors>
          <certificates src="@raw/my_ca"/>
      </trust-anchors>
  </domain-config>
</network-security-config>
						

Data Saver

ConnectivityManager.isActiveNetworkMetered()

ConnectivityManager.getRestrictBackgroundStatus()

Changed behavior

file://

Doze

Multi-language support

android.test deprecation

android.permission.GET_ACCOUNTS deprecated

Chapter 5:

The mysteries

AutomaticZenRule

android.os.Health

Honorable mentions

    Vulkan

    NDK API

Reading material

Thank you!


   @Mauin
     github.com/mauin