[MUSIC PLAYING]
ADNAN BEGOVIC: For those that don't know,
here is a brief little Wikipedia entry.
We're essentially a derivative operating system
based off Android.
We add other features, but we're mostly free and open source,
and we score 160 plus devices, verses Nexus AOSP program,
which is about five devices.
Our contributor base is massive, as you can
see this Cid head over here.
Every single line in there is a name of contributor
over the past five years.
In total we have about 1,253 contributors,
that's as of August, with about 47,000 commits.
That's not [INAUDIBLE], so it's quite a large delta.
But essentially what we do is crowdsource Android
development.
We get community changes that are incoming.
We roll them into our nightly release builds
and those actually ship on devices every single night.
Today, however, we're going to be talking
about how this delta grew a little too large
and became a little bit unmanageable.
First we're going to be talking about our TreeHacks Hackaton
learnings.
We went to Stanford hackathon.
We learned a lot of things that we were a little bit ignorant
about.
We realize that OS and firmware development
is really intimidating.
There's a lot of work, few awards
and essentially we came up with a solution that
could help us get through it.
ROMAN BIRG: So TreeHacks was a weekend long
hackaton back in February and that was at Stanford.
So there was like 670 kids who attended.
And you could imagine there were some smart guys there.
There's applications from all over the United States.
So we had two guys submit an entry using the CyanogenMod
platform, and we went there, and that's what we tried to do.
We wanted to get people to hack on it.
And so we had two entries.
Here is the winner, CyanTranslate.
And these guys built-- they went from synching
the source, to building it, to adding a whole new feature
in three days.
And we learned that that's a lot to do
and a lot to absorb in just a short amount of time.
So these guys had basically just one day
they spent trying to get the source.
We bought some hard drives to make it go by faster,
but CyanogenMod source is 25 gigabytes.
It's going to take some time.
And then they spent the next day getting familiar with it,
with the build system, trying to figure out
the different quirks.
And they didn't have that much time left to code.
They didn't need it, to be honest.
And that said something to us.
So overall we had a great time helping the kids,
getting it set up.
But we noticed that most the time we
weren't helping them with very Android specific things
that we were there for.
We helped get them set up with the build system
and just weird little quirks and things like that.
So this is their project.
I hope it pays.
So what these guys did was they came up
with an on-the-fly translator.
They hooked into CyanogenMod, and they hooked it up
to Google Translate.
And so it works from the MMS app,
and they're going to show you how
it works from the web browser.
And they do this in the span of one day.
So we got a lot of feedback from these guys, and it was great.
They love the open platform.
They love that they could just go and contribute to our Gerrit
and see all of the submissions, and everything's on GitHub.
They can go see.
They can go look at the code.
We even have some documentation that helped them get started.
But it wasn't enough.
But some of the downsides that we saw
was that it took them way too long to get started,
and that's something we took to heart.
We want to fix this.
It's a huge codebase that's 25 gigs of source,
then you have another 50 when you're building,
and then there's 100 plus packages
that you just have to look at, and it's a ton of code.
And the thing is the barrier of entry
doesn't have to be that high.
And we really tried.
We took this feedback heart, and we went
and we asked ourselv-- we came up with these questions on how
do we improve this experience.
We wanted to decrease the barrier to entry
to allow these kids to not have to have
all this tribal knowledge of how the platform works
to submit a feature.
We wanted to help streamline the process
and formalize it on how people contribute to us.
And also we wanted to stabilize our own interfaces inside.
Like, if we wanted to use our own features we could,
but what if the versioning is changed?
And what if we change something on the device we shipped,
and our code didn't--.
We didn't have these things figured out quite properly.
So this is the moral of story.
OS development is intimidating.
If you've ever managed to include a fully functioned
interface, you'd be one of the few people who
understood the process from a full stack perspective.
And that's a hard thing to do.
So one of these biggest features in CyanogenMod
was the Profiles contribution.
So Profiles was added by Martin Long in 2014.
And Profiles-- you could essentially
register for specific events in the system,
and then you could configure your device to react to them.
So, for example, here's an example
of a user creating an action to be triggered by an event.
So specifically the event being a Wi-Fi SSID connect event.
So from the Settings app, the user
is setting up on the Wi-Fi connect of their choice.
When the SSID connects, they hit the Profile Service.
The Profile Service tells the system,
hey, when this Wi-Fi SSID connects,
send it back to the profile system,
and the profile will trigger the actions back
that user has selected.
So could my app have used this Profile System?
No, not without weird crappy Java reflection,
which we try to avoid as much we can.
For the Android compatibility documents,
they say that any public method in Android namespace that
is not part of the Android-- public API
must be marked the @hide annotation.
ADNAN BEGOVIC: So the dreaded @hide-- @hide essentially
is just Javadoc annotation, specific to Android build 10.
the way it works is any methods you
don't want the public API you annotate
them with @hide and then during compile
do they get stripped from the API stubs.
It gets stripped from the Javadocs,
and essentially it's only accessible via reflection
during runtime, if you're creating interfaces that way,
which is bad practice, I guess, for us.
What implications that had for us, something like Profiles.
If we wanted to extend that to, let's
say, applications we were working in separate teams
or with someone externally.
We couldn't actually do that because there'd
be no stable interfaces.
I couldn't tell you that, hey, you make this API call,
you'll get this result back, because we
didn't have any explicit versioning at that time.
We also made QA a really horrible experience
because we couldn't set any testing expectations
based on versioning releases.
And then, honestly, just horrible rebase conflicts.
Every single time a new version of Android
came out we'd have to go and replay all the
commits that created the service and everything that
came on top of it.
Just became way too much .
So with that we kind of sat down and said,
how do we get around this.
So we came out the CyanogenMod platform.
So it's a new, more approachable infrastructure.
And the way it works is we duplicate the Android
framework.
So we essentially have three components here-- the platform
library, a secondary resource package,
and then a statically linkable SDK.
The platform library essentially hosts all the system services
that we get spun up by the system server, within Android.
So pretty much anything that does state management,
like the Profile Service, or anything
that we need to rely on being there and interacting with,
is hosted and lives here.
We're just leveraging Android's powerful IPC framework
for that.
Secondary to that, we also have a resource package.
So if ever we want to just even have a system where we're
going to reuse across applications,
we now have a very specific identifier
we can query those resources with, or drawables,
or anything in between.
We'd also declare our own permissions
that we carry on forward without platform releases.
But the biggest point here is the platform SDK.
So this essentially a jar you can just
toss into your project.
These are the stable interfaces that
can invoke the system binder calls,
and you'll actually have access to these features.
And this actually goes on a rolling release schedule.
So we take this new platform and we go back to back
to the hackathons.
Recently, we actually did another event
that's done by IDEAA, it's called Code Rush.
And then we went down to Mountain View for Hack
the Planet, which-- really smart kids there.
Came up with a lot of cool projects.
And our feedback was a lot different this time.
It's consumable.
And ease of use gets tossed around.
Our bottlenecks ended up just being logistics.
So we didn't enough CM devices there
we didn't have emulator images, which
we're working on currently.
But one such contribution we had from one of the interfaces
we added is we allowed the user-- or the developer
now-- to create tiles programmatically.
And one team who is creating a QR code application--
essentially a bitcoin wallet-- they said,
it would be great if I didn't have to go access my app
and go to all of my account settings
and go find this QR code.
So essentially they just publish their QR code
to the Quick Settings panel, go in the expanded mode
and anyone could scan it.
So it's things like this so we can allow now.
Roman's going to cover how to actually utilize
the SDK in your app.
ROMAN BIRG: So utilizing it is actually--
I had a good experience trying it
the first time after everything was in place.
It was just as easy as I had hoped.
So all you do is fire up Android Studio, start up a new project,
and you're ready to go.
So we have our version 2.0, which is our stable release
right now, the SDK.
And to compile against that version you would include
the compile 'org.cyanogenmod:platform', you
hit version 2.0.
We are on a rolling release.
The next version will be 3, so if you
want to work against our development branches,
you can set that up in your bulid.gradel,
and now you can use the SDK.
All you have is define the dependency in your build.gradle
and Maven will pull it down, sync it,
and you can hit our SDKs.
So I'm going to jump right into the code here
of how to add a custom tile.
So this works very similarly to how
you would post a notification.
So when you when you click on a notification and intent
gets fired, the first thing we do
is we need a pending intent to wrap it.
And you can see I'm creating a new intent there
with a custom action that I'll be listening for later on
and I can respond to.
Then I use the custom tile builder to create the tile.
I give it the label, the icon.
I tell it I want it to collapse after I click it
for my specific use case.
And then the last thing is I can just
tell the CMStatusBarManager to go, hey publish this tile.
I give it a unique identifier within my app
and it will show up.
On the other end, responding to the click of the tile,
you define that listener in the AndroidManifest
that listens to the action which I defined in the intent
in the previous slide.
And then in the code all it's doing
is it just removes itself.
You can come up with whatever you want.
Use your imagination.
There's so many things you can do.
Now I want to bring this back to the profiles.
So CyanogenMod chips with three profiles by default.
There's an automobile one, a default one,
and the silent profile.
I usually set my car up to automatically switch
to the automobile one when it hooks up to my car Bluetooth.
But I wanted it to do something more.
Like sometimes in the car I want an icon
to show up so I don't have to go digging through all my apps.
Like maybe I want to open Google Maps or something.
So to do that you can listen for profile state changes,
and you get sent this intent which is in our SDK.
You listen for the profile selected intent and then
when I receive that I know the profile has changed
I'm going to act upon it.
In the code you'll notice how similar this
looks to the other side and I wanted
it to be just that simple.
All we do is we check if the car profile is active.
If it is then publish my car custom shortcut tile.
If it's not then it gets removed.
It's just as simple as that.
ADNAN BEGOVIC: Going back to how did
we deal with creating a versioning system.
So we kind of decided to mirror the entire build class
from Android.
If you're familiar checking API levels programmatically,
this is one to one from that.
Essentially what we're querying is an SDK integer that's
exported as a system properties from the file
system in your current environment
or whatever device you're running on.
And you can create against a hard coded API level
to see feature's available.
So this way we can actually check like hey,
are we running on a CyanogenMod device at all.
And if we're running on a CyanogenMod device
there's an API level that's greater
than when this was introduced, and that essentially
allows us to interact with the Profile Service.
Currently we're on API level two as our stable release, which
is called Boysenberry.
We have a lot of features actually included in there,
and we continuously add a lot more.
Every single quarter we will publish documentation on this,
and currently we also host full Java docs on GitHub.
Contributing is still very much similar
to how it's always been to CyanogenMod,
and it's very core and fundamental
to how our AOSP has worked.
You essentially repo init the main manifest.
You pull it down, repo synch it, and you
start your local changes.
You can contribute it back to us,
and we actually put this in a little bit more scrutiny
than we do other code, mostly because we
want to retain the compatibility,
mostly in terms of CTS.
For those unfamiliar, CTS is a certification testing suite
that Google has you run to make sure
that you can actually get GMS services and things like that.
So we make sure that all those interfaces are stable before we
even look at your code.
We'll actually ask you to write unit tests.
We'll pretty much have you put in all the legwork
to make sure that your contribution is stable.
Then if it does get included in you'd become
part of the rolling release.
And then at the end of the quarter usually
your future gets included.
We actually had a guy from Portugal--
he's very big into multisend.
At this time Marshmallow was not released.
So he wanted to have multisend APIs.
So he pretty much wrote his entire interface
so his application could talk to his own interface
that he created in the operating system.
And he actually released his app on the Play store recently,
and he contributed that full interface to us.
But for now, I'm going to open up the floor for questions
if anyone's got some.
[INAUDIBLE]?
AUDIENCE: When will the custom file
data guys support rich content?
ADNAN BEGOVIC: When they will support what?
AUDIENCE: Rich content.
ADNAN BEGOVIC: Oh, rich content?
AUDIENCE: [INAUDIBLE]
ADNAN BEGOVIC: You know more than the people in this room.
ROMAN BIRG: Work in progress.
ADNAN BEGOVIC: So on a staging branch right now
we have a pretty cool feature that essentially lets
you render an or external processes surface within a view
container in your hierarchy.
So it lets you actually get like rich content.
If you wanted to render a map view from another app
or get that bound into your view argue,
it's actually something we're actively working on.
Good.
ROMAN BIRG: So I put up some samples for my code
that I have.
It'll actually run.
It'll actually publish a title that you can play with.
The link is down there-- the bit.ly link.
And the CM SDK, it's got a wiki.
I encourage you to go there.
Wiki, API links.
It's got great documentation.
I highly encourage you guys to go check out.
ADNAN BEGOVIC: Thank you guys for coming out.
AUDIENCE: Thanks.
[APPLAUSE]
[MUSIC PLAYING]