First Google Glass App – Part 8 – Hello Glass!

Jumping right in, let’s create a Glass GDK project from scratch:

  1. Create New Android Project
  2. Configure GDK
  3. Imports
  4. Code
  5. qwe

To create a new project…See our Part 1 of the tutorial.

Make sure to configure the Glass GDK Sneak Peek Manually if it didn’t get configured by Android Studio or Eclipse on set up.  As it turns out, even if you create a project setting GDK as the Compile for API, it doesn’t get created as such.  You must double check in your build.gradle file (CAREFUL, there are 2 such files.  You need to modify your inner most gradle file) and make sure it looks something like this:

Google Glass GDK App Build Gradle File Settings by Marcio Valenzuela Santiapps.com
Google Glass GDK App Build Gradle File Settings by Marcio Valenzuela Santiapps.com

And you need to make sure that Android 4.0.3 GDK Sneak Peek & gdk.jar got added to your External Libraries as well.

Ok, once we have that out of the way, we need to include some imports.  In this case we need to add AudioManager support because we will be working with audio.  We also need TextToSpeech for recognizing commands and KeyEvent to respond to touches.

Add the following imports:

import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.view.View;
import android.view.KeyEvent;
import android.widget.TextView;

import com.google.android.glass.app.Card;
import com.google.android.glass.media.Sounds;

We will create the card and its view as well as add a TextView, nothing new here.  But we will create a TextToSpeech variable as well as a context.  We init our speech engine and pass it the value to be speak.

We will also be creating an onKeyDown method to respond to taps on the touchpad.  When they DO occur we will then create an AudioManager to play a tap sound, set the text view and also set speak a new value.

So lets add the following code:

public class HelloGlassActivity extends Activity {

private Card _card;
private View _cardView;
private TextView _statusTextView;

private TextToSpeech _speech;

private Context _context = this;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Init TextToSpeech engine
_speech = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
_speech.speak(“Hello Glass”, TextToSpeech.QUEUE_FLUSH, null);
}
});

// An alternative way to layout the UX
setContentView(R.layout.layout_helloworld);
_statusTextView = (TextView)findViewById(R.id.status);
}

/**
* Handle the tap from the touchpad.
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
// Handle tap events.
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:

// Status message below the main text in the alternative UX layout
AudioManager audio = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
audio.playSoundEffect(Sounds.TAP);

_statusTextView.setText(R.string.touchpad_touched);

_speech.speak(“Touchpad touched”, TextToSpeech.QUEUE_FLUSH, null);

return true;
default:
return super.onKeyDown(keyCode, event);
}
}

@Override
public void onResume() {
super.onResume();
}

@Override
public void onPause() {
super.onPause();
}

@Override
public void onDestroy() {
super.onDestroy();
}
}

Its quite a simple app but it gets your juices flowing!

Plug in your Glass device and hit the Run button!

iOS7 Sprite Kit for Game Design for iPhone & iPad

iOS 7 Series – Sprite Kit

Welcome to iOS7 and to start off, I want to kick things off with SpriteKit.  Although it deals with video games, many companies are using iOS apps as a marketing tactic to engage their users in an effort to promote their products.

SpriteKit is the most prominent feature in iOS7 so we’re going to take a quick tour.  Go ahead and create a New Project in XCode5 and select the SpriteKit template (the bottom right icon):

iOS7 SpriteKit Basics by Marcio Valenzuela Santiapps.com
iOS7 SpriteKit Basics by Marcio Valenzuela Santiapps.com

Click next and fill in your project data.  Once you are in the main XCode window notice we have the following files in the Project Navigator:

1)   AppDelegate

2)   Main.Storyboard

3)   ViewController

4)   MyScene

If you look in the AppDelegate you will see nothing new, just a UIWindow property.  The Main.Storyboard is even more eerie.  It’s nothing more than a blank scene.  Then you find the ViewController.h file, which basically imports the SpriteKit framework.  If you check in your Target Linked Libraries you can see SpriteKit in linked.

ViewController.m is where things get interesting.

– (void)viewDidLoad

{

[super viewDidLoad];

// Configure the view.

SKView * skView = (SKView *)self.view;

skView.showsFPS = YES;

skView.showsNodeCount = YES;

// Create and configure the scene.

SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];

scene.scaleMode = SKSceneScaleModeAspectFill;

// Present the scene.

[skView presentScene:scene];

}

In viewDidLoad we create an SKView object and assign our viewcontroller’s view to it.  As an SKView type view, we have a property that allows us to display the fps onscreen and another one for viewing the nodes onscreen for debugging purposes.

We now create a second object of type SKScene and instantiate it with the size of our SKView object to make sure it fits.  Then we set the SKScene object’s scaleMode to AspectFill.  Finally we tell our SKView object to present our SKScene object each with its set properties.

There are a couple of extra methods that tell the app to autorotate and returns the supported orientations.

Now let’s move on to the MyScene object created because this is where the magic happens.

-(id)initWithSize:(CGSize)size {

if (self = [super initWithSize:size]) {

/* Setup your scene here */

self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];

SKLabelNode *myLabel = [SKLabelNode labelNodeWithFontNamed:@”Chalkduster”];

myLabel.text = @”Hello, World!”;

myLabel.fontSize = 30;

myLabel.position = CGPointMake(CGRectGetMidX(self.frame),

CGRectGetMidY(self.frame));

[self addChild:myLabel];

}

return self;

}

First we create an instance of self with the passed in value for size.  Next we set the background color and create a label in order to position it in the middle of the screen.

The next method reacts to screen touches using the well known touchesBegan method.

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

/* Called when a touch begins */

for (UITouch *touch in touches) {

CGPoint location = [touch locationInNode:self];

SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:@”Spaceship”];

sprite.position = location;

SKAction *action = [SKAction rotateByAngle:M_PI duration:1];

[sprite runAction:[SKAction repeatActionForever:action]];

[self addChild:sprite];

}

}

Here we loop through any touches and get their location as a CGPoint.  Then we instantiate a sprite from a file named Spaceship and set its position to the touch received.  Finally we create a rotating action and run it on the sprite and add that now rotating sprite to our SKScene.  Voila.

However, there is a very important method left out, the update method.  This method gets called every so often, many times a second actually!  So this is the method used to execute our game logic.

So let’s assume we are the Head iOS Programmer for a big soda company and you met with the Marketing Director about making a game to promote your product.  You decide game will be really simple, such as trying to catch a soda can falling from the sky at the beach.  What you need:

a)    A beach backdrop

b)   A soda can

c)    A potential client

d)   You also need a good marketing strategy to go with the game, otherwise playing the game won’t amount to much.  Such a strategy could be whoever makes the most points in the next month, gets a free 24pack or something.  But you better check with your Marketing Director first J

iOS7 SpriteKit Basics by Marcio Valenzuela Santiapps.com
iOS7 SpriteKit Basics
iOS7 SpriteKit Basics by Marcio Valenzuela Santiapps.com
iOS7 SpriteKit Basics
iOS7 SpriteKit Basics by Marcio Valenzuela Santiapps.com
iOS7 SpriteKit Basics Sprites

So let’s go ahead and google some images:

Ok so let’s plop these on screen to make sure the sizes are proportional.  We are going to be making this project for an iPhone Retina screen so the correct beach size should be the complete screen size, which is 960×640.  To put the beach image on the screen, aside from importing it into your project:

iOS7 SpriteKit Basics by Marcio Valenzuela Santiapps.com
iOS7 SpriteKit Basics

We need to add the code.  So let’s move over to our MyScene initWithSize method because that is only called once and we don’t need to change the background for this game after its been created the first time.  First remove the entire code inside the if block and replace it:

SKSpriteNode *background = [SKSpriteNode spriteNodeWithImageNamed:@”beach.png”];

background.anchorPoint = CGPointZero;

background.position = CGPointZero;

[self addChild:background];

This created a sprite called background using the beach image.  It positions the image and adds it to the scene.  If you run it you’ll get a chopped off image because the simulator is positioned vertically.  This is because we didn’t tell the app to only run in landscape mode.  So head over to your Target Settings and uncheck all orientations except Landscape Left.

iOS7 SpriteKit Basics by Marcio Valenzuela Santiapps.com
iOS7 SpriteKit Basics

FIRST NOTE: Orientation must be defined.

Now run it again and you’ll get a huge image as the background and possibly only part of it being displayed.  This is because you must tell Xcode that the image is to be used in Retina devices.  You do this by renaming the images beach@2x.png.  So go ahead and rename the image in Finder and you’ll have to remove the reference and re-add it as beach@2x.png.  Voila!

iOS7 SpriteKit Basics by Marcio Valenzuela Santiapps.com
iOS7 SpriteKit Basics

Ok so far so good!  Notice we get the node and fps count on the right bottom corner.

NOTE: Retina images are named filename@2x.png

Let’s go ahead and place the cooler on the screen to see if it looks right.  This time remember to rename your images before importing them.  After importing it, let’s add the following code, again in the initWithSize method because we only need to add the cooler once:

// ADD COOLER

SKSpriteNode *cooler = [SKSpriteNode spriteNodeWithImageNamed:@”cooler@2x.png”];

cooler.anchorPoint = CGPointZero;

cooler.position = CGPointZero;

[self addChild:cooler];

Just for your reference, my cooler png is 125×131, almost a square.  I added it and it looks fine:

iOS7 SpriteKit Basics by Marcio Valenzuela Santiapps.com
iOS7 SpriteKit Basics

As you can see, node count went up to 2 and fps has no reason to change so far.  There is something important to note here, and it’s that the cooler was added in the bottom left corner.  If you review the code, we set both the background and the cooler’s anchorPoint to CGPointZero, which is equal to 0,0.  This corresponds to the bottom left of the screen.  Thus when we position the cooler, we are telling it to put the cooler’s bottom left corner (its anchor), in the screen’s bottom left corner (its position).

NOTE: CGPointZero in SpriteKit = (0,0) = Bottom Left Corner

Ok now let’s think about the logic.  Both the background and the cooler need only appear once.  The soda can however might need to appear more than once because once the user catches the first one, we probably want to give him a second one to catch, otherwise it’ll be a short and disappointing game.  This is where the game structure gets interesting.  We won’t simply add the soda can in the initWithSize method but rather outsource its creation to a separate method.  Let’s create a method called createSodaCan:

-(void)createSodaCan{

// ADD CAN

SKSpriteNode *can = [SKSpriteNode spriteNodeWithImageNamed:@”sodacan@2x.png”];

can.anchorPoint = CGPointMake(CGRectGetMidX(can.frame), CGRectGetMidY(can.frame));

can.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));

[self addChild:can];

}

Here we are setting the can’s anchor point to its center and placing it in the center of the screen using CGPointMake and CGRectGetMidX/Y.  However if you run the app there won’t be a soda can anywhere onscreen because we haven’t called it.  One place to call it would be in a method such as the touchesBegan method, but let’s try something different.  In your initWithSize method, add the following code right after the cooler code:

//Delay to call can method

[NSTimer scheduledTimerWithTimeInterval:2.0

target:self

selector:@selector(createSodaCan)

userInfo:nil

repeats:NO];

This basically calls the createSodaCan method after 2 seconds of initializing the scene.  And two seconds after, there it is:

iOS7 SpriteKit Basics by Marcio Valenzuela Santiapps.com
iOS7 SpriteKit Basics

NOTE: Game logic can be fired off from the init method of your scene or from a user interaction method such as the touchesBegan method.

Great!  Now let’s think of what we want to do.  Im thinking we could do something like:

1)   Center the cooler at the bottom of the screen

2)   Move the soda can up to the top

3)   Have the can move from top to bottom

Ok great, so let’s do the first two, which should be quite simple.  Then we’ll worry about moving the can.  The first step is the cooler, so replace the cooler code with:

// ADD COOLER

SKSpriteNode *cooler = [SKSpriteNode spriteNodeWithImageNamed:@”cooler@2x.png”];

cooler.anchorPoint = CGPointMake(CGRectGetMidX(cooler.frame), CGRectGetMidY(cooler.frame));

cooler.position = CGPointMake(self.frame.size.width*0.5, self.frame.size.height*0.01);

[self addChild:cooler];

This will place the cooler at 50% the width of the screen and about 1% from bottom to top.  Now do something similar with the can except that we want it to be on top so it can drop:

// ADD CAN

SKSpriteNode *can = [SKSpriteNode spriteNodeWithImageNamed:@”sodacan@2x.png”];

can.anchorPoint = CGPointMake(CGRectGetMidX(can.frame), CGRectGetMidY(can.frame));

can.position = CGPointMake(self.frame.size.width/2, self.frame.size.height*0.75);

[self addChild:can];

This places the can halfway across from left to right and ¾ of the way up the screen:

iOS7 SpriteKit Basics by Marcio Valenzuela Santiapps.com
iOS7 SpriteKit Basics

NOTE: We use relative positioning of an object in the view’s frame to avoid offscreen or misplaced images on different sized screens.

Perfect!  Now how do we animate the can so it can fall?  Well there are two ways, one is using physics, which requires us to create a physics-body object and assign it to the soda can and then “turn on” gravity so to speak.  The much simpler way is to animate the can to go from the top of the screen to the bottom of the screen.

To use the latter, we need SKActions much like the rotate action in the template.  So let’s code some and see what happens.  Well I took a look at the way the template created the rotating action and started typing…XCode took care of the rest.  I reasoned that what I wanted was to “move” the sprite and XCode suggested the following:

//Move the can

SKAction *fallingAction = [SKAction moveByX:<#(CGFloat)#> y:<#(CGFloat)#> duration:<#(NSTimeInterval)#>]

So I went with that and ended up with this code for the createSodaCan method:

// ADD CAN

SKSpriteNode *can = [SKSpriteNode spriteNodeWithImageNamed:@”sodacan@2x.png”];

can.anchorPoint = CGPointMake(CGRectGetMidX(can.frame), CGRectGetMidY(can.frame));

can.position = CGPointMake(self.frame.size.width/2, self.frame.size.height*0.75);

//Move the can

SKAction *fallingAction = [SKAction moveByX:0 y:-400 duration:2.0];

[can runAction:fallingAction];

[self addChild:can];

Well that’s not half bad.  I could’ve used another method such as moveTo instead of moveBy.

Ok now let’s simulate how to actually “catch” the can in the cooler.  What we need is something called “collision detection”.  What we want to do is check to see if the rectangle around the cooler is intersecting with the rectangle around the can.  To do this, we have to do so constantly.  That’s where the update method comes in.  This method is called repeatedly before each frame is drawn.  So we need to ask it if those two rectangles are colliding.  That means we need references to both objects.  To do that we create an instance variable for each, so we add them in MyScene.h:

@interface MyScene : SKScene {

SKSpriteNode *cooler;

SKSpriteNode *can;

}

Now modify the code in initWithSize by removing the type declaration in each line where we create the cooler and the can so they look like:

cooler = [SKSpriteNode spriteNodeWithImageNamed:@”cooler@2x.png”];

can = [SKSpriteNode spriteNodeWithImageNamed:@”sodacan@2x.png”];

And now we can access those objects through their pointers in the update method as well.  So add this line to your update method:

//Check for intersection of frames for collision simulation

[self testCollisionOfSprite:can withSprite:cooler];

This means this line will be called every time the update method fires.  You can even add an NSLog into the update method to get an idea of how many times its called.  Now let’s define the testCollisionOfSprite:withSprite: method:

-(void)testCollisionOfSprite:(SKSpriteNode*)sprite1 withSprite:(SKSpriteNode*)sprite2{

CGRect sprite1Rect = [self getSizeOfSprite:sprite1];

CGRect sprite2Rect = [self getSizeOfSprite:sprite2];

if (CGRectIntersectsRect(sprite1Rect, sprite2Rect)) {

NSLog(@”They collided”);

}

}

Nothing special going on here, we are simply creating a rectangle for each of the 2 sprites passed in and checking if those rectangles intersect.  If they do, we log.  Finally the way we get those rectangles around the sprites:

– (CGRect) getSizeOfSprite:(SKSpriteNode*)sprite{

double sx = sprite.position.x;

double sy = sprite.position.y;

return CGRectMake(sx, sy, sprite.frame.size.width, sprite.frame.size.height);

}

We have a game…almost.  Let’s add some sound and make the can disappear.

Import your favorite sound and add this code right after the NSLog for They Collided:

SKAction *play = [SKAction playSoundFileNamed:@”explosion_small.caf” waitForCompletion:YES];

[can runAction:play];

can.alpha = 0;

As you noticed earlier, the collision happens many times because there is a long trajectory form the moment the rectangles begin overlapping until they stop overlapping.  This results in a repetitive sound, which is annoying.  More importantly if becomes a problem if you want to work with scoring points because if you try to +1 a point when the collision occurs, you actually end up with many more points in total!  So what is usually done in these cases is a work around that creates a BOOL flag from the start and sets it to False.  We do this in MyScene.h:

BOOL collisionOccurred;

then in the createSodaCan method we set it to FALSE:

collisionOccurred = FALSE;

Finally we modify the if test like so:

if (CGRectIntersectsRect(sprite1Rect, sprite2Rect) && !collisionOccurred) {

collisionOccurred = TRUE;

NSLog(@”They collided”);

SKAction *play = [SKAction playSoundFileNamed:@”explosion_small.caf” waitForCompletion:YES];

[can runAction:play];

can.alpha = 0;

}

This way we always check to see if collisionOccurred is FALSE, if it is then we set it to TRUE inside the if, do our stuff, thus collisionOccurred will not be FALSE again until we set it back.

It is a cumbersome solution because then you must make sure you re-set your flag to FALSE everytime you create a new can.  It even worse if you don’t really create more cans.  Many times for memory saving reasons, we simply don’t destroy the original can.  If you noticed I didn’t destroy the node, I simply made it invisible.  The reason is that now I can reuse that sprite again by repositioning it on top and making it visible again thus saving processor power.  This is a very common tactic in games where you want to have lots of enemies or coins or what not and you don’t want to have to create thousands of instances of them.

The other more elegant solution to the collision detection repetition issue is the first method we talked about collision detection.  So let’s try to cover that in as simple terms as possible.

Physics & Collision Detection

Physics introduces the notion of physical bodies that will be “attached” to our sprite nodes.  Those bodies can be of type dynamic, static or edges.  A dynamic body reacts to physics, static bodies react to physics except forces and collisions because they are meant not to move yet exist in a physical world.  Edges never move and they are usually used to represent boundaries in a game.

iOS7 SpriteKit Basics by Marcio Valenzuela Santiapps.com
iOS7 SpriteKit Basics

This means that we can try to match a physics body to a sprite node identically, such as:

iOS7 SpriteKit Basics by Marcio Valenzuela Santiapps.com
iOS7 SpriteKit Basics

which results in a very complex physics body to monitor vs simply using a tall rectangle which results in a much easier body to manipulate.  A circle is actually the easiest body to use.

So let’s start off by creating a border around our screen by adding this line at the end of our initWithSize method:

//Create border

self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];

and in the createSodaCan method add these lines to the end:

can.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:can.size.width/2];

can.physicsBody.dynamic = YES;

What we have done is create a second physicsBody for the can this time and made it of circular shape and assigned it a dynamic property.  Now let’s remove the line in the update method that calls for testCollisionOfSprite:withSprite: because we don’t need that anymore.  Now run the app and you should see the soda can actually stop near the bottom of the screen which is where the border should be.  But the border is invisible, isn’t it?  Go ahead and comment out the border line in the init method and see for yourself J.

Ok so now let’s remove our line that made the can move from top to bottom:

//[can runAction:fallingAction];

And now let gravity do the work for you, add this line at the end of your initWithSize method:

//Set Gravity

self.physicsWorld.gravity = CGPointMake(0.0, -9.8);

Cool!  But the can didn’t bounce quite so much huh!?  Well that’s probably what a can would do.  But just for fun, let’s say it was a rubber can.  Add this line after the can’s dynamic physicsBody setting to YES:

can.physicsBody.restitution = 0.5;

Neat!  Well but we’re not gonna be covering physics now.  So turn that property off for now.  We just need physics for collision detection.  This is done via collision groups.

First we adopt the SKPhysicsContactDelegate Protocol so we can set out scene as the delegate to receive notifications of collisions:

@interface MyScene : SKScene <SKPhysicsContactDelegate>{

First we set our scene as the delegate in the initWithSize method:

self.physicsWorld.contactDelegate = self;

Now we must set the categories in our can and cooler objects.  So after the cooler sprite creation in the initWithSize method, add this code to create a physics body for it and set its category mask:

//collision physics

cooler.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:cooler.size];

cooler.physicsBody.dynamic = YES;

cooler.physicsBody.categoryBitMask = coolerCategory;

cooler.physicsBody.collisionBitMask = canCategory;

cooler.physicsBody.contactTestBitMask = canCategory;

So we create a rectangular body instead of a circle and set its category to cooler but its collision mask to canCategory.

Likewise in the can creation method (createSodaCan) we use this code:

//Add physics body to can

can.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:can.size.width/2];

can.physicsBody.dynamic = YES;

//can.physicsBody.restitution = 0.5;

can.physicsBody.categoryBitMask = canCategory;

can.physicsBody.collisionBitMask = coolerCategory;

can.physicsBody.contactTestBitMask = coolerCategory;

As mentioned before, we set this body as a circle but commented out the restitution property for now.  We set its category to can and its collision mask to cooler.  We must define those categories above the @implementation line like so:

//DONT COLLIDE

static const uint32_t canCategory =  0x1 << 0;

static const uint32_t coolerCategory =  0x1 << 1;

Finally, we override the beginContact method of the protocol which reads:

//COLLISION PHYSICS

– (void)didBeginContact:(SKPhysicsContact *)contact

{

SKPhysicsBody *firstBody, *secondBody;

if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)

{

firstBody = contact.bodyA;

secondBody = contact.bodyB;

}

else {

firstBody = contact.bodyB;

secondBody = contact.bodyA;

}

if ((firstBody.categoryBitMask & coolerCategory) != 0)

{

NSLog(@”They collisionated!”);

}

}

We pass in a contact, then create 2 body references which will come in as part of that contact.  We set the contact bodies to either one and test for a collision and log something in the console.

Well this is as far as SpriteKit basics can get.  There are more advanced topics such as advanced physics, forces, particles, animations, parallax and raycasting that could be material for a Part 2 should there be enough interest in the subject.

First Google Glass App – Part 7 – Bridge to Glass App GDK Development

Before jumping into Glass dev, let’s understand how to create a Hello World project in Android Studio (AS) and run it on our device.

  1. Create New Project
  2. Get to know the guts
  3. Add Imports
  4. Add Code
  5. Tweak guts
  6. Run on Device

Create New Project

When you select New Project from the File Menu, you get this Wizard screen:

Android Studio Beginner App Development by Marcio Valenzuela Santiapps.com
Android Studio Beginner App Development

Fill in the Application Name in a natural language and the Module Name without spaces.  Make sure to select API 15 for Minimum and Target SDK but Glass Development Kit Sneak Peek for Compile with.

Click Next and in the next screen just leave everything as is (the launch icon selector screen).

Android Studio Project Launcher Icon Window by Marcio Valenzuela Santiapps.com
Android Studio Project Launcher Icon Window

After that screen, leave the Blank Activity option selected and again click Next.

Android Studio Project Blank Activity Window by Marcio Valenzuela Santiapps.com
Android Studio Project Blank Activity Window

Finally in the Activity Name, leave MainActivity.  In the Layout Name leave activity_main but also copy that activity_main over to the Fragment Layout Name, replacing fragment_main.

Android Studio Project Layout Window by Marcio Valenzuela Santiapps.com
Android Studio Project Layout Window

Everything else stays as is and Click Finish.  The reason for this last bit is that new in Android is this concept of Fragments.  This just complicates things for us at the moment so we will leave it out for now.  We must also remove the MainActivity.java fragment method later.

Android Guts

Let’s familiarize ourselves with this screen:

Android Studio Layout Google Glass Development by Marcio Valenzuela Santiapps.com
Android Studio Layout Google Glass Development

Let’s review these 10 top pointers:

  1. Your Java Classes or Android Activities
  2. Layout files in xml format
  3. Value files for storing global settings of sorts
  4. AndroidManifest is a sort of Central Registry
  5. Top level build.gradle file
  6. Low level build.gradle file
  7. Tab bar for displayed files
  8. Sync Gradle file button
  9. Run button
  10. Green = A-Ok button!
Take some time to explore these files.  If you have gone through the tutorial at:
 
http://developer.android.com/training/basics/firstapp/index.html
 
You will be familiar with these pointers.  Otherwise, let’s take a closer look.
 
MainActivity is selected and displayed in the editor window.  This contains your default, boilerplate/template created MainActivity Class required for any app.
 
The layout folder contains your activity_main.xml file.  If you look inside that file you will see an xml file with some parameters and a TextView element.  You will also see a graphical representation of it off to the far right.
 
The values folder contains more xml files.  Most importantly, the strings.xml which contains global references to string values.  These are used throughout the app to assign string values where needed.
 
The AndroidManifest.xml file contains some general settings elements for your app such as the package name, launcher icon, activity tags which contain your declared activities and in this case, if the activity has an intent, which is like an action, it must also be specified here.  In our case we will add a Voice Trigger intent filter if there isn’t one already.
 
Build.gradle files are not to be messed around with much.  This is a new M.O. used by Android Studio to organize files in a workspace.  You must keep in mind here that there is a Top level and Low level build.gradle file so make sure you know which one you are being told to put things in.
 
The tabs display whatever files you have double clicked on the File Window on the left.
 
The Sync Gradle button is that green-blue circle with a solid circle inside and a green arrow pointing down.  Go Figure!  Its basically a sort of I’ve-made-some-changes-to-the-AndroidManifest-and/or-other-project-wide-parameters-which-require-project-workspace-reindexing (phew) button!
 
The Run button is of course the one used to build and launch the app in the emulator or device.
 
The Green=AOk button tells you all file and project inconsistencies have been resolved and that the project will build and run.  Sometimes you have resolved coding issues and this box is still red.  Just tap on the Sync Gradle button mentioned before and Just Like That, Its Magic…AOk!
 
Great now let’s look at some code…
 
Imports
 
If you expand the imports “+” sign in the MainActivity window’s left edge, you will get a list of what imports a project comes with.  Let’s just make sure they look like this:
 

import android.app.Activity;
import android.os.Bundle;
import com.google.android.glass.app.Card;

The last import as you can see is what allows us to create a Card instance, which is what Glass apps are based on.  This is what you put your info into in a Glass app.

Code

Next, simply add this method inside your public class MainActivity extends Activity statement:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

Card card = new Card(this);
card.setText(“你 好 吗”);
card.setFootnote(“santiapps.com”);

setContentView(card.toView());
}

Here we are creating a new card, setting its text and footnote properties and setting its view to the Activity’s ContentView or the main view.

Voila!  Connect your Glass to your USB port, make sure to set it to Debug Mode ON and Run the app.  It will build and install on your Glass.

Tweak

Now let’s tweak it.  In your AndroidManifest, declare this intent by making that file look like this:

<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
package=”com.santiapps.glassapp” >

<application
android:allowBackup=”true”
android:icon=”@drawable/ic_launcher”
android:label=”@string/app_name” >
<activity
android:name=”com.santiapps.glassapp.MainActivity”
android:label=”@string/app_name” >
<intent-filter>
<action android:name=”com.google.android.glass.action.VOICE_TRIGGER” />
</intent-filter>
<meta-data android:name=”com.google.android.glass.VoiceTrigger”
android:resource=”@xml/voice_trigger” />
</activity>
</application>

</manifest>

I’ve pasted my entire file here so as to clear up as much as I can.  Basically you just need to add the intent-filter and its metadata elements.

Let’s make it more interesting!  As with our First Android App tutorial, let’s add some user interaction in Part 2.