Sunday, June 30, 2013

Example to use YouTubePlayerFragment of YouTube Android Player API

Example to use YouTubePlayerFragment of YouTube Android Player API

Example to use YouTubePlayerFragment of YouTube Android Player API


Follow the step in "YouTube Android Player API step-by-step" to Download and import YouTube Android Player API, and Register your app using YouTube Android Player API and obtain API Key. To use YouTubePlayerFragment, you have to define android:minSdkVersion="11" or higher in your AndroidManifest.xml.

Modify /res/layout/activity_main.xml to define layout, with <fragment> of "com.google.android.youtube.player.YouTubePlayerFragment".
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <fragment
        android:name="com.google.android.youtube.player.YouTubePlayerFragment"
        android:id="@+id/youtubeplayerfragment"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold"
        android:layout_gravity="center_horizontal"
        android:autoLink="web" />
    
    <ScrollView 
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout 
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <Button
                android:id="@+id/btnviewfullscreen"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="View in Full Screen" />
            <TextView 
                android:id="@+id/videolog"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
            
        </LinearLayout>
    </ScrollView>
    
</LinearLayout>


Create /res/layout-land/activity_main.xml to define layout in Landscape orientation.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="horizontal"
    tools:context=".MainActivity" >

    <fragment
        android:name="com.google.android.youtube.player.YouTubePlayerFragment"
        android:id="@+id/youtubeplayerfragment"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="3"/>
    <LinearLayout 
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_weight="1">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="http://android-er.blogspot.com/"
            android:textStyle="bold"
            android:layout_gravity="center_horizontal"
            android:autoLink="web" />
        
        <ScrollView 
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <LinearLayout 
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">
                <Button
                    android:id="@+id/btnviewfullscreen"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="View in Full Screen" />
                <TextView 
                    android:id="@+id/videolog"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" />
            </LinearLayout>
  </ScrollView>
    </LinearLayout>
</LinearLayout>


MainActivity.java
package com.example.androidyoutubeapiplayer;

import com.google.android.youtube.player.YouTubeBaseActivity;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayer.PlaybackEventListener;
import com.google.android.youtube.player.YouTubePlayerFragment;
import com.google.android.youtube.player.YouTubePlayer.PlayerStateChangeListener;
import com.google.android.youtube.player.YouTubePlayer.Provider;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends YouTubeBaseActivity implements 
 YouTubePlayer.OnInitializedListener{
 
 public static final String API_KEY = "AIzaSyCe6tORd9Ch4lx-9Ku5SQ476uS9OtZYsWA";
 public static final String VIDEO_ID = "o7VVHhK9zf0";
 
 private YouTubePlayer youTubePlayer;
 private YouTubePlayerFragment youTubePlayerFragment;
 private TextView textVideoLog;
 private Button btnViewFullScreen;
 
 private static final int RQS_ErrorDialog = 1;
 
 private MyPlayerStateChangeListener myPlayerStateChangeListener;
 private MyPlaybackEventListener myPlaybackEventListener;
 
 String log = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        youTubePlayerFragment = (YouTubePlayerFragment)getFragmentManager()
             .findFragmentById(R.id.youtubeplayerfragment);
        youTubePlayerFragment.initialize(API_KEY, this);

        textVideoLog = (TextView)findViewById(R.id.videolog);
        
        myPlayerStateChangeListener = new MyPlayerStateChangeListener();
        myPlaybackEventListener = new MyPlaybackEventListener();
        
        btnViewFullScreen = (Button)findViewById(R.id.btnviewfullscreen);
        btnViewFullScreen.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    youTubePlayer.setFullscreen(true);
   }});
    }

 @Override
 public void onInitializationFailure(Provider provider,
   YouTubeInitializationResult result) {
  
  if (result.isUserRecoverableError()) {
   result.getErrorDialog(this, RQS_ErrorDialog).show(); 
  } else {
   Toast.makeText(this, 
     "YouTubePlayer.onInitializationFailure(): " + result.toString(), 
     Toast.LENGTH_LONG).show(); 
  }
 }

 @Override
 public void onInitializationSuccess(Provider provider, YouTubePlayer player,
   boolean wasRestored) {
  
  youTubePlayer = player;
  
  Toast.makeText(getApplicationContext(), 
    "YouTubePlayer.onInitializationSuccess()", 
    Toast.LENGTH_LONG).show();
  
  youTubePlayer.setPlayerStateChangeListener(myPlayerStateChangeListener);
  youTubePlayer.setPlaybackEventListener(myPlaybackEventListener);
  
  if (!wasRestored) {
        player.cueVideo(VIDEO_ID);
      }

 }
 
 private final class MyPlayerStateChangeListener implements PlayerStateChangeListener {
  
  private void updateLog(String prompt){
   log +=  "MyPlayerStateChangeListener" + "\n" + 
     prompt + "\n\n=====";
   textVideoLog.setText(log);
  };

  @Override
  public void onAdStarted() {
   updateLog("onAdStarted()");
  }

  @Override
  public void onError(
    com.google.android.youtube.player.YouTubePlayer.ErrorReason arg0) {
   updateLog("onError(): " + arg0.toString());
  }

  @Override
  public void onLoaded(String arg0) {
   updateLog("onLoaded(): " + arg0);
  }

  @Override
  public void onLoading() {
   updateLog("onLoading()");
  }

  @Override
  public void onVideoEnded() {
   updateLog("onVideoEnded()");
  }

  @Override
  public void onVideoStarted() {
   updateLog("onVideoStarted()");
  }
  
 }
 
 private final class MyPlaybackEventListener implements PlaybackEventListener {
  
  private void updateLog(String prompt){
   log +=  "MyPlaybackEventListener" + "\n-" + 
     prompt + "\n\n=====";
   textVideoLog.setText(log);
  };

  @Override
  public void onBuffering(boolean arg0) {
   updateLog("onBuffering(): " + String.valueOf(arg0));
  }

  @Override
  public void onPaused() {
   updateLog("onPaused()");
  }

  @Override
  public void onPlaying() {
   updateLog("onPlaying()");
  }

  @Override
  public void onSeekTo(int arg0) {
   updateLog("onSeekTo(): " + String.valueOf(arg0));
  }

  @Override
  public void onStopped() {
   updateLog("onStopped()");
  }
  
 }

}

download filesDownload the files.

Download APK to try on your device.



The tutorial: YouTube Android Player API step-by-step

Friday, June 28, 2013

Embed html using Google Maps JavaScript API v3 in Android App

The Google Maps Javascript API Version 3 is now the official Javascript API. Version 2 of this API has been officially deprecated as per our deprecation policy.

The Google Maps Javascript API lets you embed Google Maps in your own web pages. Version 3 of this API is especially designed to be faster and more applicable to mobile devices, as well as traditional desktop browser applications.

The API provides a number of utilities for manipulating maps (just like on the http://maps.google.com web page) and adding content to the map through a variety of services, allowing you to create robust maps applications on your website.

The JavaScript Maps API V3 is a free service, available for any web site that is free to consumers. Please see the terms of use for more information.




It's easy to embed WebView, load with HTML using Google Maps JavaScript API v3, in Android App:



Create /assets/simplemap.html, copy from Simple Map example in Google Maps JavaScript API v3, html code with Google Maps JavaScript API v3.
<!DOCTYPE html>
<html>
  <head>
    <title>Simple Map</title>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
    <meta charset="utf-8">
    <style>
      html, body, #map-canvas {
        margin: 0;
        padding: 0;
        height: 100%;
      }
    </style>
    <script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
    <script>
var map;
function initialize() {
  var mapOptions = {
    zoom: 8,
    center: new google.maps.LatLng(-34.397, 150.644),
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  map = new google.maps.Map(document.getElementById('map-canvas'),
      mapOptions);
}

google.maps.event.addDomListener(window, 'load', initialize);

    </script>
  </head>
  <body>
    <div id="map-canvas"></div>
  </body>
</html>


Modify /res/layout/activity_main.xml, to add <WebView> in layout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold"
        android:layout_gravity="center_horizontal"
        android:autoLink="web" />
    <WebView
        android:id="@+id/mybrowser"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>


MainActivity.java
package com.example.androidsimplemap;

import android.os.Bundle;
import android.app.Activity;
import android.webkit.WebView;

public class MainActivity extends Activity {
 
 WebView myBrowser;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  myBrowser = (WebView)findViewById(R.id.mybrowser);
  myBrowser.loadUrl("file:///android_asset/simplemap.html");
  myBrowser.getSettings().setJavaScriptEnabled(true);
 }

}


Note that, in order for your Activity to access the Internet and load web pages in a WebView, you must add the INTERNET permissions to your Android Manifest file:

<uses-permission android:name="android.permission.INTERNET"/>



add@2014-05-22:

download filesDownload the files.

Download and try the APK.

Free eBook: First preview: Programming Windows Store Apps with HTML, CSS, and JavaScript, Second Edition

Microsoft Press provide a First Preview of the upcoming second edition of Kraig Brockschmidt’s Programming Windows Store Apps with HTML, CSS, and JavaScript!

First preview: Programming Windows Store Apps with HTML, CSS, and JavaScript, Second Edition

The 255-page PDF itself can be downloaded here: http://aka.ms/SecondEdition/FirstPreview (5.57 MB)

FYI, EPUB and MOBI for the ebook’s final release will be provided, not for the two preliminary releases.

Also, please remember that this material is in DRAFT form. This content will not be final until the ebook’s final release.

Source: Microsoft Press Blog

Thursday, June 27, 2013

Force YouTube Android Player to run in full screen mode

TO force YouTube Android Player to run in full screen mode, simple call setFullscreen(true) method of the YouTubePlayer object.

Force YouTube Android Player to run in full screen mode


Modify from last exercise "Handle player state changes and playback events, by implementing PlayerStateChangeListener and PlaybackEventListener.", to add a Button in layout, to force running in Full Screen mode.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold"
        android:layout_gravity="center_horizontal"
        android:autoLink="web" />
    
    <ScrollView 
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout 
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <com.google.android.youtube.player.YouTubePlayerView
                android:id="@+id/youtubeplayerview"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="5dp" />
            <Button
                android:id="@+id/btnviewfullscreen"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="View in Full Screen" />
            <TextView 
                android:id="@+id/videolog"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
            
        </LinearLayout>
    </ScrollView>
    
</LinearLayout>


Force running in Full Screen mode by calling youTubePlayer.setFullscreen(true).
package com.example.androidyoutubeapiplayer;

import com.google.android.youtube.player.YouTubeBaseActivity;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayer.PlaybackEventListener;
import com.google.android.youtube.player.YouTubePlayerView;
import com.google.android.youtube.player.YouTubePlayer.PlayerStateChangeListener;
import com.google.android.youtube.player.YouTubePlayer.Provider;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends YouTubeBaseActivity implements 
 YouTubePlayer.OnInitializedListener{
 
 public static final String API_KEY = "AIzaSyCe6tORd9Ch4lx-9Ku5SQ476uS9OtZYsWA";
 public static final String VIDEO_ID = "o7VVHhK9zf0";
 
 private YouTubePlayer youTubePlayer;
 private YouTubePlayerView youTubePlayerView;
 private TextView textVideoLog;
 private Button btnViewFullScreen;
 
 private static final int RQS_ErrorDialog = 1;
 
 private MyPlayerStateChangeListener myPlayerStateChangeListener;
 private MyPlaybackEventListener myPlaybackEventListener;
 
 String log = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        youTubePlayerView = (YouTubePlayerView)findViewById(R.id.youtubeplayerview);
        youTubePlayerView.initialize(API_KEY, this);

        textVideoLog = (TextView)findViewById(R.id.videolog);
        
        myPlayerStateChangeListener = new MyPlayerStateChangeListener();
        myPlaybackEventListener = new MyPlaybackEventListener();
        
        btnViewFullScreen = (Button)findViewById(R.id.btnviewfullscreen);
        btnViewFullScreen.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    youTubePlayer.setFullscreen(true);
   }});
    }

 @Override
 public void onInitializationFailure(Provider provider,
   YouTubeInitializationResult result) {
  
  if (result.isUserRecoverableError()) {
   result.getErrorDialog(this, RQS_ErrorDialog).show(); 
  } else {
   Toast.makeText(this, 
     "YouTubePlayer.onInitializationFailure(): " + result.toString(), 
     Toast.LENGTH_LONG).show(); 
  }
 }

 @Override
 public void onInitializationSuccess(Provider provider, YouTubePlayer player,
   boolean wasRestored) {
  
  youTubePlayer = player;
  
  Toast.makeText(getApplicationContext(), 
    "YouTubePlayer.onInitializationSuccess()", 
    Toast.LENGTH_LONG).show();
  
  youTubePlayer.setPlayerStateChangeListener(myPlayerStateChangeListener);
  youTubePlayer.setPlaybackEventListener(myPlaybackEventListener);
  
  if (!wasRestored) {
        player.cueVideo(VIDEO_ID);
      }

 }
 
 private final class MyPlayerStateChangeListener implements PlayerStateChangeListener {
  
  private void updateLog(String prompt){
   log +=  "MyPlayerStateChangeListener" + "\n" + 
     prompt + "\n\n=====";
   textVideoLog.setText(log);
  };

  @Override
  public void onAdStarted() {
   updateLog("onAdStarted()");
  }

  @Override
  public void onError(
    com.google.android.youtube.player.YouTubePlayer.ErrorReason arg0) {
   updateLog("onError(): " + arg0.toString());
  }

  @Override
  public void onLoaded(String arg0) {
   updateLog("onLoaded(): " + arg0);
  }

  @Override
  public void onLoading() {
   updateLog("onLoading()");
  }

  @Override
  public void onVideoEnded() {
   updateLog("onVideoEnded()");
  }

  @Override
  public void onVideoStarted() {
   updateLog("onVideoStarted()");
  }
  
 }
 
 private final class MyPlaybackEventListener implements PlaybackEventListener {
  
  private void updateLog(String prompt){
   log +=  "MyPlaybackEventListener" + "\n-" + 
     prompt + "\n\n=====";
   textVideoLog.setText(log);
  };

  @Override
  public void onBuffering(boolean arg0) {
   updateLog("onBuffering(): " + String.valueOf(arg0));
  }

  @Override
  public void onPaused() {
   updateLog("onPaused()");
  }

  @Override
  public void onPlaying() {
   updateLog("onPlaying()");
  }

  @Override
  public void onSeekTo(int arg0) {
   updateLog("onSeekTo(): " + String.valueOf(arg0));
  }

  @Override
  public void onStopped() {
   updateLog("onStopped()");
  }
  
 }

}


download filesDownload the files.

Download APK to try on your device.



The Tutorial: YouTube Android Player API step-by-step

Android Studio 0.1.8 just released

Android Studio 0.1.8 just released to address several bugs in 0.1.7 around gradle builds. In addition, there are the following changes:
  • Support for running instrumentation tests on device. Tests should be created in the folder "src/instrumentTest/java" (of the main application or a library) following the conventions described at http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Testing
    • To run them, simply right click on the test and click on Run as type Android Junit test.
    • You can also create a new run configuration of type "Android Test" and specify whether you want to run all the tests in a module, package, class or just a single test.
    • NOTE: Debugging tests will be supported in the next release
  • 0.1.8 also comes with a brand new implementation of a resource manager in the IDE, used for layout preview, editor resource folding, etc. This should address many bugs reported in earlier versions (such as @id attributes not being handled properly in RelativeLayouts, bugs with opening layouts after making edits, etc, and should be more performant.
  • New lint check validating device admin receivers

Details: Android Tools Project Site - Android Studio 0.1.8 Released

Tuesday, June 25, 2013

Handle player state changes and playback events, by implementing PlayerStateChangeListener and PlaybackEventListener.

To keep track with events and states of Android YouTubePlayer, implement PlayerStateChangeListener and PlaybackEventListener.

Handle player state changes and playback events


Modify from last exercise "Handle initialization error YouTube API Service".

Modify activity_main.xml to add a TextView in layout, to display our log.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold"
        android:layout_gravity="center_horizontal"
        android:autoLink="web" />
    
    <ScrollView 
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout 
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <com.google.android.youtube.player.YouTubePlayerView
                android:id="@+id/youtubeplayerview"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="5dp" />
            <TextView 
                android:id="@+id/videolog"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
            
        </LinearLayout>
    </ScrollView>
    
</LinearLayout>


Modify MainActivity.java, to implement PlayerStateChangeListener and PlaybackEventListener.
package com.example.androidyoutubeapiplayer;

import com.google.android.youtube.player.YouTubeBaseActivity;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayer.PlaybackEventListener;
import com.google.android.youtube.player.YouTubePlayerView;
import com.google.android.youtube.player.YouTubePlayer.PlayerStateChangeListener;
import com.google.android.youtube.player.YouTubePlayer.Provider;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends YouTubeBaseActivity implements 
 YouTubePlayer.OnInitializedListener{
 
 public static final String API_KEY = "AIzaSyCe6tORd9Ch4lx-9Ku5SQ476uS9OtZYsWA";
 public static final String VIDEO_ID = "o7VVHhK9zf0";
 
 private YouTubePlayer youTubePlayer;
 private YouTubePlayerView youTubePlayerView;
 private TextView textVideoLog;
 
 private static final int RQS_ErrorDialog = 1;
 
 private MyPlayerStateChangeListener myPlayerStateChangeListener;
 private MyPlaybackEventListener myPlaybackEventListener;
 
 String log = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        youTubePlayerView = (YouTubePlayerView)findViewById(R.id.youtubeplayerview);
        youTubePlayerView.initialize(API_KEY, this);

        textVideoLog = (TextView)findViewById(R.id.videolog);
        
        myPlayerStateChangeListener = new MyPlayerStateChangeListener();
        myPlaybackEventListener = new MyPlaybackEventListener();
    }

 @Override
 public void onInitializationFailure(Provider provider,
   YouTubeInitializationResult result) {
  
  if (result.isUserRecoverableError()) {
   result.getErrorDialog(this, RQS_ErrorDialog).show(); 
  } else {
   Toast.makeText(this, 
     "YouTubePlayer.onInitializationFailure(): " + result.toString(), 
     Toast.LENGTH_LONG).show(); 
  }
 }

 @Override
 public void onInitializationSuccess(Provider provider, YouTubePlayer player,
   boolean wasRestored) {
  
  youTubePlayer = player;
  
  Toast.makeText(getApplicationContext(), 
    "YouTubePlayer.onInitializationSuccess()", 
    Toast.LENGTH_LONG).show();
  
  youTubePlayer.setPlayerStateChangeListener(myPlayerStateChangeListener);
  youTubePlayer.setPlaybackEventListener(myPlaybackEventListener);
  
  if (!wasRestored) {
        player.cueVideo(VIDEO_ID);
      }

 }
 
 private final class MyPlayerStateChangeListener implements PlayerStateChangeListener {
  
  private void updateLog(String prompt){
   log +=  "MyPlayerStateChangeListener" + "\n" + 
     prompt + "\n\n=====";
   textVideoLog.setText(log);
  };

  @Override
  public void onAdStarted() {
   updateLog("onAdStarted()");
  }

  @Override
  public void onError(
    com.google.android.youtube.player.YouTubePlayer.ErrorReason arg0) {
   updateLog("onError(): " + arg0.toString());
  }

  @Override
  public void onLoaded(String arg0) {
   updateLog("onLoaded(): " + arg0);
  }

  @Override
  public void onLoading() {
   updateLog("onLoading()");
  }

  @Override
  public void onVideoEnded() {
   updateLog("onVideoEnded()");
  }

  @Override
  public void onVideoStarted() {
   updateLog("onVideoStarted()");
  }
  
 }
 
 private final class MyPlaybackEventListener implements PlaybackEventListener {
  
  private void updateLog(String prompt){
   log +=  "MyPlaybackEventListener" + "\n-" + 
     prompt + "\n\n=====";
   textVideoLog.setText(log);
  };

  @Override
  public void onBuffering(boolean arg0) {
   updateLog("onBuffering(): " + String.valueOf(arg0));
  }

  @Override
  public void onPaused() {
   updateLog("onPaused()");
  }

  @Override
  public void onPlaying() {
   updateLog("onPlaying()");
  }

  @Override
  public void onSeekTo(int arg0) {
   updateLog("onSeekTo(): " + String.valueOf(arg0));
  }

  @Override
  public void onStopped() {
   updateLog("onStopped()");
  }
  
 }

}


download filesDownload the files.

Download APK to try on your device.



The Tutorial: YouTube Android Player API step-by-step

Monday, June 24, 2013

Introducing Google Play for Education

BizDevBytes: Introducing Google Play for Education
As Google expands its education offering to Android, Shazia Makhdumi provides an overview of the Google Play for Education program. Developers will learn how the program works and how to leverage the unique business opportunities in creating educational apps for the K-12 market.

To learn more visit developer.android.com/edu

Handle initialization error YouTube API Service

Refer to the exercises of "Simple example using YouTube Android Player API" and "YouTubeThumbnailView example", onInitializationFailure() methods will be called with YouTubeInitializationResult passed if fail in initialization.

If the error is is user-recoverable (isUserRecoverableError() == true), we can proceed by calling getErrorDialog(Activity, int), and then show this dialog to enable users to recover from this error.

Handle initialization error YouTube API Service

Modify MainActivity.java from last exercise "YouTubeThumbnailView example of YouTube Android Player API" to handle onInitializationFailure() for YouTubePlayer and YouTubeThumbnailView.
package com.example.androidyoutubeapiplayer;

import com.google.android.youtube.player.YouTubeBaseActivity;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayerView;
import com.google.android.youtube.player.YouTubePlayer.Provider;
import com.google.android.youtube.player.YouTubeThumbnailLoader;
import com.google.android.youtube.player.YouTubeThumbnailLoader.ErrorReason;
import com.google.android.youtube.player.YouTubeThumbnailView;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;

public class MainActivity extends YouTubeBaseActivity implements
YouTubePlayer.OnInitializedListener, YouTubeThumbnailView.OnInitializedListener{
 
 public static final String API_KEY = "AIzaSyCe6tORd9Ch4lx-9Ku5SQ476uS9OtZYsWA";
 public static final String VIDEO_ID = "o7VVHhK9zf0";
 
 private YouTubePlayer youTubePlayer;
 private YouTubePlayerView youTubePlayerView;
 private YouTubeThumbnailView youTubeThumbnailView;
 private YouTubeThumbnailLoader youTubeThumbnailLoader;
 
 private static final int RQS_ErrorDialog = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        youTubePlayerView = (YouTubePlayerView)findViewById(R.id.youtubeplayerview);
        youTubePlayerView.initialize(API_KEY, this);
        
        youTubeThumbnailView = (YouTubeThumbnailView)findViewById(R.id.youtubethumbnailview);
        youTubeThumbnailView.initialize(API_KEY, this);
        youTubeThumbnailView.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    if(youTubePlayer != null){
     youTubePlayer.play();
    }
   }});
    }

 @Override
 public void onInitializationFailure(Provider provider,
   YouTubeInitializationResult result) {
  
  if (result.isUserRecoverableError()) {
   result.getErrorDialog(this, RQS_ErrorDialog).show(); 
  } else {
   Toast.makeText(this, 
     "YouTubePlayer.onInitializationFailure(): " + result.toString(), 
     Toast.LENGTH_LONG).show(); 
  }
 }

 @Override
 public void onInitializationSuccess(Provider provider, YouTubePlayer player,
   boolean wasRestored) {
  
  youTubePlayer = player;
  
  Toast.makeText(getApplicationContext(), 
    "YouTubePlayer.onInitializationSuccess()", 
    Toast.LENGTH_LONG).show();
  
  if (!wasRestored) {
        player.cueVideo(VIDEO_ID);
      }
 }

 @Override
 public void onInitializationFailure(YouTubeThumbnailView thumbnailView, 
   YouTubeInitializationResult result) {

  if (result.isUserRecoverableError()) {
   result.getErrorDialog(this, RQS_ErrorDialog).show(); 
  } else {
   Toast.makeText(this, 
     "YouTubeThumbnailView.onInitializationFailure(): " + result.toString(), 
     Toast.LENGTH_LONG).show(); 
  }
 }

 @Override
 public void onInitializationSuccess(YouTubeThumbnailView thumbnailView, 
   YouTubeThumbnailLoader thumbnailLoader) {
  
  Toast.makeText(getApplicationContext(), 
    "YouTubeThumbnailView.onInitializationSuccess()", 
    Toast.LENGTH_LONG).show();
  
  youTubeThumbnailLoader = thumbnailLoader;
  thumbnailLoader.setOnThumbnailLoadedListener(new ThumbnailLoadedListener());
       
  youTubeThumbnailLoader.setVideo(VIDEO_ID);
  
 }
 
 private final class ThumbnailLoadedListener implements
    YouTubeThumbnailLoader.OnThumbnailLoadedListener {

  @Override
  public void onThumbnailError(YouTubeThumbnailView arg0, ErrorReason arg1) {
   Toast.makeText(getApplicationContext(), 
     "ThumbnailLoadedListener.onThumbnailError()", 
     Toast.LENGTH_LONG).show();
  }

  @Override
  public void onThumbnailLoaded(YouTubeThumbnailView arg0, String arg1) {
   Toast.makeText(getApplicationContext(), 
     "ThumbnailLoadedListener.onThumbnailLoaded()", 
     Toast.LENGTH_LONG).show();
   
  }
  
 }

}


download filesDownload the files.

Download APK to try on your device.

Next: Handle player state changes and playback events, by implementing PlayerStateChangeListener and PlaybackEventListener.


The Tutorial: YouTube Android Player API step-by-step

Sunday, June 23, 2013

YouTubeThumbnailView example of YouTube Android Player API

Extend the exercise of "Simple example using YouTube Android Player API", add YouTubeThumbnailView. When the YouTubeThumbnailView clicked, start play the YouTubePlayer.

YouTubeThumbnailView

Modify layout file, activity_main.xml, to add <YouTubePlayerView>.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold"
        android:layout_gravity="center_horizontal"
        android:autoLink="web" />
    
    <ScrollView 
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout 
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            
            <com.google.android.youtube.player.YouTubeThumbnailView
                android:id="@+id/youtubethumbnailview"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="5dp" />
            <com.google.android.youtube.player.YouTubePlayerView
                android:id="@+id/youtubeplayerview"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="5dp" />
            
        </LinearLayout>
    </ScrollView>
    
</LinearLayout>


MainActivity.java
package com.example.androidyoutubeapiplayer;

import com.google.android.youtube.player.YouTubeBaseActivity;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayerView;
import com.google.android.youtube.player.YouTubePlayer.Provider;
import com.google.android.youtube.player.YouTubeThumbnailLoader;
import com.google.android.youtube.player.YouTubeThumbnailLoader.ErrorReason;
import com.google.android.youtube.player.YouTubeThumbnailView;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;

public class MainActivity extends YouTubeBaseActivity implements
YouTubePlayer.OnInitializedListener, YouTubeThumbnailView.OnInitializedListener{
 
 public static final String API_KEY = "AIzaSyCe6tORd9Ch4lx-9Ku5SQ476uS9OtZYsWA";
 public static final String VIDEO_ID = "o7VVHhK9zf0";
 
 private YouTubePlayer youTubePlayer;
 private YouTubePlayerView youTubePlayerView;
 private YouTubeThumbnailView youTubeThumbnailView;
 private YouTubeThumbnailLoader youTubeThumbnailLoader;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        youTubePlayerView = (YouTubePlayerView)findViewById(R.id.youtubeplayerview);
        youTubePlayerView.initialize(API_KEY, this);
        
        youTubeThumbnailView = (YouTubeThumbnailView)findViewById(R.id.youtubethumbnailview);
        youTubeThumbnailView.initialize(API_KEY, this);
        youTubeThumbnailView.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    if(youTubePlayer != null){
     youTubePlayer.play();
    }
   }});
    }

 @Override
 public void onInitializationFailure(Provider provider,
   YouTubeInitializationResult result) {
  Toast.makeText(getApplicationContext(), 
    "YouTubePlayer.onInitializationFailure()", 
    Toast.LENGTH_LONG).show();
 }

 @Override
 public void onInitializationSuccess(Provider provider, YouTubePlayer player,
   boolean wasRestored) {
  
  youTubePlayer = player;
  
  Toast.makeText(getApplicationContext(), 
    "YouTubePlayer.onInitializationSuccess()", 
    Toast.LENGTH_LONG).show();
  
  if (!wasRestored) {
        player.cueVideo(VIDEO_ID);
      }
 }

 @Override
 public void onInitializationFailure(YouTubeThumbnailView thumbnailView, 
   YouTubeInitializationResult error) {
  
  Toast.makeText(getApplicationContext(), 
    "YouTubeThumbnailView.onInitializationFailure()", 
    Toast.LENGTH_LONG).show();
  
 }

 @Override
 public void onInitializationSuccess(YouTubeThumbnailView thumbnailView, 
   YouTubeThumbnailLoader thumbnailLoader) {
  
  Toast.makeText(getApplicationContext(), 
    "YouTubeThumbnailView.onInitializationSuccess()", 
    Toast.LENGTH_LONG).show();
  
  youTubeThumbnailLoader = thumbnailLoader;
  thumbnailLoader.setOnThumbnailLoadedListener(new ThumbnailLoadedListener());
       
  youTubeThumbnailLoader.setVideo(VIDEO_ID);
  
 }
 
 private final class ThumbnailLoadedListener implements
    YouTubeThumbnailLoader.OnThumbnailLoadedListener {

  @Override
  public void onThumbnailError(YouTubeThumbnailView arg0, ErrorReason arg1) {
   Toast.makeText(getApplicationContext(), 
     "ThumbnailLoadedListener.onThumbnailError()", 
     Toast.LENGTH_LONG).show();
  }

  @Override
  public void onThumbnailLoaded(YouTubeThumbnailView arg0, String arg1) {
   Toast.makeText(getApplicationContext(), 
     "ThumbnailLoadedListener.onThumbnailLoaded()", 
     Toast.LENGTH_LONG).show();
   
  }
  
 }

}


download filesDownload the files.

Download APK to try on your device.

Next: Handle initialization error YouTube API Service


The Tutorial: YouTube Android Player API step-by-step

Saturday, June 22, 2013

Convert Uri return from Gallery to file path

The old exercise "Select Image using Android build-in Gallery" show how to selecte photo using Gallery app, in Uri form. In this exercise, the returned Uri is converted to file path in String form.

Convert Uri return from Gallery to file path

I also show using deprecated managedQuery() method for API under level 11, and CursorLoader() method for API level 11 or higher.

Layout file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold"
        android:layout_gravity="center_horizontal"
        android:autoLink="web" />
    
    <Button
        android:id="@+id/loadimage" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="Load Image"/>
    <TextView 
        android:id="@+id/targeturi" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" />
    <TextView 
        android:id="@+id/targetpath1" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" />
    <TextView 
        android:id="@+id/targetpath2" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" />
</LinearLayout>


MainActivity.java
package com.example.androidselectimage;

import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.app.Activity;
import android.content.CursorLoader;
import android.content.Intent;
import android.database.Cursor;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
 
 TextView textTargetUri, textTargetPath1, textTargetPath2;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  Button buttonLoadImage = (Button)findViewById(R.id.loadimage);
        textTargetUri = (TextView)findViewById(R.id.targeturi);
        textTargetPath1 = (TextView)findViewById(R.id.targetpath1);
        textTargetPath2 = (TextView)findViewById(R.id.targetpath2);
        
        buttonLoadImage.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    Intent intent = new Intent(Intent.ACTION_PICK, 
      android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(intent, 0);
   }});
 }

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  // TODO Auto-generated method stub
  super.onActivityResult(requestCode, resultCode, data);
  
  if (resultCode == RESULT_OK){
   Uri targetUri = data.getData();
   textTargetUri.setText("Uri: " + targetUri.toString());
   textTargetPath1.setText("path: " + getPathFromUri_managedQuery(targetUri));
   textTargetPath2.setText("path: " + getPathFromUri_CursorLoader(targetUri));
  }
 }
 
 //using deprecated managedQuery() method 
 private String getPathFromUri_managedQuery(Uri uri){
  String [] projection = {MediaStore.Images.Media.DATA};
  
        Cursor cursor = managedQuery( 
          uri, 
          projection,
          null,   //selection
          null,   //selectionArgs
          null   //sortOrder
        );
        
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();

        return cursor.getString(column_index);
 }

 //using CursorLoader() method for API level 11 or higher
 private String getPathFromUri_CursorLoader(Uri uri){
  
  String [] projection = {MediaStore.Images.Media.DATA};
  
  CursorLoader cursorLoader = new CursorLoader(
    getApplicationContext(),
    uri, 
          projection,
          null,   //selection
          null,   //selectionArgs
          null   //sortOrder
        );
  
  Cursor cursor = cursorLoader.loadInBackground();
  
  int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();

        return cursor.getString(column_index);    
 }
}


Note: To use CursorLoader() in your code, you have to modify AndroidManifest.xml to speciify android:minSdkVersion="11".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.androidselectimage"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.androidselectimage.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


download filesDownload the files.

Friday, June 21, 2013

Start activity once notification clicked

In the exercise "Generate Notification with sound when alarm received", a browse opened and load a specified url once user click on the notification. We can also pass intent to start activity to notification, to start activity once user click on the notification.

Start activity once notification clicked

Modify AlarmReceiver.java in the exercise "Generate Notification with sound when alarm received", pass Intent(context, DoSomething.class) to PendingIntent.getActivity(...).
package com.example.androiddatepicker;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.widget.Toast;

public class AlarmReceiver extends BroadcastReceiver {
 
 private static final int MY_NOTIFICATION_ID=1;
 NotificationManager notificationManager;
 Notification myNotification;

 @Override
 public void onReceive(Context context, Intent intent) {
  Toast.makeText(context, "Alarm received!", Toast.LENGTH_LONG).show();

     Intent myIntent = new Intent(context, DoSomething.class);
     PendingIntent pendingIntent = PendingIntent.getActivity(
            context, 
            0, 
            myIntent, 
            Intent.FLAG_ACTIVITY_NEW_TASK);
     
     myNotification = new NotificationCompat.Builder(context)
       .setContentTitle("Exercise of Notification!")
       .setContentText("Do Something...")
       .setTicker("Notification!")
       .setWhen(System.currentTimeMillis())
       .setContentIntent(pendingIntent)
       .setDefaults(Notification.DEFAULT_SOUND)
       .setAutoCancel(true)
       .setSmallIcon(R.drawable.ic_launcher)
       .build();
     
     notificationManager = 
       (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
     notificationManager.notify(MY_NOTIFICATION_ID, myNotification);
 }

}


Create DoSomething.java, it will be started once user click the notification.
package com.example.androiddatepicker;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.Toast;

public class DoSomething extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  ImageView image = new ImageView(this);
  image.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher));
  setContentView(image);
  Toast.makeText(getApplicationContext(), 
    "Do Something NOW", 
    Toast.LENGTH_LONG).show();
 }

}


Modify AndroidManifest.xml to add <activity> of "DoSomething".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.androiddatepicker"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.androiddatepicker.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.example.androiddatepicker.DoSomething"
            android:label="@string/app_name" >
        </activity>
        <receiver android:name=".AlarmReceiver" android:process=":remote" />
    </application>

</manifest>


download filesDownload the files.

Thursday, June 20, 2013

java.lang.RuntimeException: Unable to instantiate activity ComponentInfo

Problem on Java Build Path again...! similar to the case of Unexpected namespace prefix "xmlns" found for tag fragment on xmlns:map="http://schemas.android.com/apk/res-auto".

Somebody report that my old exercise "Share IntentService among Fragments" not work. So I try to import the downloaded project in a new installed Android ADT, and the following error...sss reported in LogCat:

06-20 23:34:38.358: W/dalvikvm(26472): Unable to resolve superclass of Lcom/example/androidyahooweatherdom/MainActivity; (10)
06-20 23:34:38.358: W/dalvikvm(26472): Link of class 'Lcom/example/androidyahooweatherdom/MainActivity;' failed
06-20 23:34:38.358: W/dalvikvm(26472): threadid=1: thread exiting with uncaught exception (group=0x40cb92d0)
06-20 23:34:38.363: E/AndroidRuntime(26472): FATAL EXCEPTION: main
06-20 23:34:38.363: E/AndroidRuntime(26472): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.androidyahooweatherdom/com.example.androidyahooweatherdom.MainActivity}: java.lang.ClassNotFoundException: com.example.androidyahooweatherdom.MainActivity
06-20 23:34:38.363: E/AndroidRuntime(26472):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2267)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at android.app.ActivityThread.access$600(ActivityThread.java:151)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1331)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at android.os.Handler.dispatchMessage(Handler.java:99)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at android.os.Looper.loop(Looper.java:155)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at android.app.ActivityThread.main(ActivityThread.java:5485)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at java.lang.reflect.Method.invokeNative(Native Method)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at java.lang.reflect.Method.invoke(Method.java:511)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:795)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at dalvik.system.NativeStart.main(Native Method)
06-20 23:34:38.363: E/AndroidRuntime(26472): Caused by: java.lang.ClassNotFoundException: com.example.androidyahooweatherdom.MainActivity
06-20 23:34:38.363: E/AndroidRuntime(26472):  at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:61)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at android.app.Instrumentation.newActivity(Instrumentation.java:1069)
06-20 23:34:38.363: E/AndroidRuntime(26472):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2258)
06-20 23:34:38.363: E/AndroidRuntime(26472):  ... 11 more


Finally, I solve it by correcting Java Build Path - right clicking project -> Java Build Path, select Order and Export tab, check to include both Android 4.2.2 and Android Private Libraries, and click OK.

correct Java Build Path

Actually, I don't know what happen! May be there are something changed in new Android Developer Tools.

Simple example using YouTube Android Player API

Simple example using YouTube Android Player API

Before create app using YouTube Android Player API, you have to "Download and import YouTube Android Player API" and "Register your app using YouTube Android Player API and obtain API Key".

Modify layout xml to add view of <com.google.android.youtube.player.YouTubePlayerView>.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold"
        android:layout_gravity="center_horizontal"
        android:autoLink="web" />
    
    <com.google.android.youtube.player.YouTubePlayerView
        android:id="@+id/youtubeplayerview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>


Modify MainActivity.java, extends YouTubeBaseActivity implements YouTubePlayer.OnInitializedListener.
package com.example.androidyoutubeapiplayer;

import com.google.android.youtube.player.YouTubeBaseActivity;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayerView;
import com.google.android.youtube.player.YouTubePlayer.Provider;

import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends YouTubeBaseActivity implements
YouTubePlayer.OnInitializedListener{
 
 public static final String API_KEY = "AIzaSyCe6tORd9Ch4lx-9Ku5SQ476uS9OtZYsWA";
 public static final String VIDEO_ID = "o7VVHhK9zf0";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        YouTubePlayerView youTubePlayerView = (YouTubePlayerView)findViewById(R.id.youtubeplayerview);
        youTubePlayerView.initialize(API_KEY, this);
    }

 @Override
 public void onInitializationFailure(Provider provider,
   YouTubeInitializationResult result) {
  Toast.makeText(getApplicationContext(), 
    "onInitializationFailure()", 
    Toast.LENGTH_LONG).show();
 }

 @Override
 public void onInitializationSuccess(Provider provider, YouTubePlayer player,
   boolean wasRestored) {
  if (!wasRestored) {
        player.cueVideo(VIDEO_ID);
      }
 }

}


Where API_KEY is the key obtained in the step of "Register your app using YouTube Android Player API and obtain API Key", VIDEO_ID is the ID of the video to play.

Permission of "android.permission.INTERNET" is needed in AndroidManifest.xml.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.androidyoutubeapiplayer"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.androidyoutubeapiplayer.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>



download filesDownload the files.

Download APK to try on your device.

Next: YouTubeThumbnailView example of YouTube Android Player API

Related: YouTube Android Player API step-by-step

Tuesday, June 18, 2013

Register your app using YouTube Android Player API and obtain API Key

To use YouTube Android Player API in your app, you have to register it and obtain API key. This post show you the steps to do so.

- Login with your Google account in Google APIs Console.

- Pull-down the Slection on left, and click Create... under Other Projects.



- Enter name of your project.



- Enable YouTube Data API v3 to ON.



- And then click to select API Access, and you will found you API key. You have to insert it in your code to use YouTube Android Player API.





To develop Android apps with YouTube Android Player API, read the posts in YouTube Android Player API step-by-step.

Unexpected namespace prefix "xmlns" found for tag fragment on xmlns:map="http://schemas.android.com/apk/res-auto"

This post share my experience on the error of Unexpected namespace prefix "xmlns" found for tag fragment on xmlns:map="http://schemas.android.com/apk/res-auto".

Recently, I re-check my old project using Google Maps Android API v2, it work without error before. But LogCat show error:

...
E/AndroidRuntime(20411): Caused by: android.app.Fragment$InstantiationException: Unable to instantiate fragment com.google.android.gms.maps.MapFragment: make sure class name exists, is public, and has an empty constructor that is public
...
E/AndroidRuntime(20411): Caused by: java.lang.ClassNotFoundException: com.google.android.gms.maps.MapFragment
...

Then I re-visit the layout xml with MapFragment, error message show Unexpected namespace prefix "xmlns" found for tag fragment on the statement  xmlns:map="http://schemas.android.com/apk/res-auto".



To solve it, correct Java Build Path by right clicking on your project -> Java Build Path, select Order and Export tab, check both Android 4.2.2 and Android Private Libraries, and click OK.


And then clean and build the project.


Similar to the case: java.lang.RuntimeException: Unable to instantiate activity ComponentInfo


Download and import YouTube Android Player API

YouTube Android Player API enables you to incorporate video playback functionality into your Android applications. The API defines methods for loading and playing YouTube videos (and playlists) and for customizing and controlling the video playback experience.

I will show the steps to develop Android App with YouTube Android Player API step-by-step, please refer the post YouTube Android Player API step-by-step.

To develop Android apps with YouTube Android Player API, you have to download and import the YouTube Android Player API jar to your project.

- New a Android Application Project.

- Download and unzip YouTube Android Player API here.

- Copy the unzipped YouTubeAndroidPlayerApi.jar file to /libs folder in your project. The YouTubeAndroidPlayerApi.jar file should be in /libs sub-folder of your unzipped files.

import YouTubeAndroidPlayerApi.jar

- Right click your project, select , then select Java Build Path and click Add JARs... button.


- Select YouTubeAndroidPlayerApi.jar, and click OK.


Sunday, June 16, 2013

Custom ArrayAdapter for Spinner, with custom icons

It repost my old exercise "Custom ArrayAdapter for Spinner, with different icons". Somebody report that the icon in the Spinner button doesn't change accordingly. I have re-check on HTC One X (running Android 4.1.1), HTC Flyer (Android 3.2.1) and Nexus One (Android 2.3.6), all work as expected. Would you help to check in your device and let me know if any problem?

APK available here: http://goo.gl/8VmK3

run on HTC One X (running Android 4.1.1)

Run on Nexus One (Android 2.3.6)



Before implement custom Spinner with icons, we have to prepare our custom icons. Download the sample icons to /drawable folder, named icon.png and icongray.png.



Create /res/layout/row.xml to define the custom row layout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:orientation="horizontal">
<ImageView
 android:id="@+id/icon"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:src="@drawable/ic_launcher"/>
<TextView
 android:id="@+id/weekofday"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>
</LinearLayout>


Modify the layout, /res/layout/activity_main.xml, to add Spinner.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold"
        android:layout_gravity="center_horizontal"
        android:autoLink="web" />
    <Spinner
        android:id="@+id/spinner"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" />

</LinearLayout>


Main code, MainActivity.java.
package com.example.androidcustomspinner;

import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;

public class MainActivity extends Activity {
 
 String[] DayOfWeek = {"Sunday", "Monday", "Tuesday", 
   "Wednesday", "Thursday", "Friday", "Saturday"};

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  Spinner mySpinner = (Spinner)findViewById(R.id.spinner);
        mySpinner.setAdapter(new MyCustomAdapter(MainActivity.this, R.layout.row, DayOfWeek));
 }

 public class MyCustomAdapter extends ArrayAdapter<String>{

  public MyCustomAdapter(Context context, int textViewResourceId,
    String[] objects) {
   super(context, textViewResourceId, objects);
   // TODO Auto-generated constructor stub
  }

  @Override
  public View getDropDownView(int position, View convertView,
    ViewGroup parent) {
   // TODO Auto-generated method stub
   return getCustomView(position, convertView, parent);
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
   // TODO Auto-generated method stub
   return getCustomView(position, convertView, parent);
  }

  public View getCustomView(int position, View convertView, ViewGroup parent) {
   // TODO Auto-generated method stub
   //return super.getView(position, convertView, parent);

   LayoutInflater inflater=getLayoutInflater();
   View row=inflater.inflate(R.layout.row, parent, false);
   TextView label=(TextView)row.findViewById(R.id.weekofday);
   label.setText(DayOfWeek[position]);
   
   ImageView icon=(ImageView)row.findViewById(R.id.icon);
   
   if (DayOfWeek[position]=="Sunday"){
    icon.setImageResource(R.drawable.icon);
   }
   else{
    icon.setImageResource(R.drawable.icongray);
   }
   
   return row;
  } 
    }
}

download filesDownload the files.

Next:
Custom Spinner with text color

Saturday, June 15, 2013

Generate Notification with sound when alarm received

The exercise "Set alarm on specified date/time with DatePicker/TimePicker" simple display Toast when alarm time reached. To generate Notification with sound when alarm received, generate Notification in AlarmReceiver.java using Notification.Builder() or NotificationCompat.Builder().

This exercise use Android Support library's NotificationCompat.Builder() to supports Android version as old as API level 4. (Right click your project > Android Tools > Add Sipport Library...)

Generate Notification with sound when alarm received


Modify AlarmReceiver.java
package com.example.androiddatepicker;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.widget.Toast;

public class AlarmReceiver extends BroadcastReceiver {
 
 private static final int MY_NOTIFICATION_ID=1;
 NotificationManager notificationManager;
 Notification myNotification;
 private final String myBlog = "http://android-er.blogspot.com/";

 @Override
 public void onReceive(Context context, Intent intent) {
  Toast.makeText(context, "Alarm received!", Toast.LENGTH_LONG).show();

     Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(myBlog));
     PendingIntent pendingIntent = PendingIntent.getActivity(
            context, 
            0, 
            myIntent, 
            Intent.FLAG_ACTIVITY_NEW_TASK);
     
     myNotification = new NotificationCompat.Builder(context)
       .setContentTitle("Exercise of Notification!")
       .setContentText("http://android-er.blogspot.com/")
       .setTicker("Notification!")
       .setWhen(System.currentTimeMillis())
       .setContentIntent(pendingIntent)
       .setDefaults(Notification.DEFAULT_SOUND)
       .setAutoCancel(true)
       .setSmallIcon(R.drawable.ic_launcher)
       .build();
     
     notificationManager = 
       (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
     notificationManager.notify(MY_NOTIFICATION_ID, myNotification);
 }

}


download filesDownload the files.

Next:
- Start activity once notification clicked

Related:
Generate Alarm, Notification and Ringtone using RingtoneManager

Friday, June 14, 2013

Android Studio 0.1.5 Released

Android Studio 0.1.5 just Released. This release contains only bug fixes and infrastructure work, as well as a merge with the latest IntelliJ 13 development branch.

~ source: https://sites.google.com/a/android.com/tools/recent/studio015released

Install/Update Android Studio:

If you are already running Android Studio, just restart it, or manually check for updates via Help > Check for Update... (on OSX, look in the Android Studio menu).

If you do not already have Android Studio, install the latest full install from
http://developer.android.com/sdk/installing/studio.html#download

Thursday, June 13, 2013

Options for DatePicker to display or hide calendar view and spinners

The former exercise show a "Simple example of using DatePicker with both calendar view and spinners". We can show/hide calendar view and spinners individually in XML with android:calendarViewShown and android:spinnersShown attributes. Introduced in API level 11, we can also program it using Java code with setCalendarViewShown() and setSpinnersShown() methods.

Options for DatePicker to display or hide calendar view and spinners


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />
    <RadioGroup
        android:id="@+id/optGroup"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
        <RadioButton
            android:id="@+id/optCalendar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="CalendarView" 
            android:checked="true" />
        <RadioButton
            android:id="@+id/optSpinners"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Spinners" />
        <RadioButton
            android:id="@+id/optBoth"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Both" />
  </RadioGroup>
    <DatePicker
        android:id="@+id/pickerdate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:calendarViewShown="true"
        android:spinnersShown="false" />

</LinearLayout>


package com.example.androiddatepickershown;

import android.os.Bundle;
import android.widget.DatePicker;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.app.Activity;

public class MainActivity extends Activity {
 
 RadioGroup groupBtn;
 RadioButton btnCalendar, btnSpinners, btnBoth;
 DatePicker pickerDate;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  groupBtn = (RadioGroup)findViewById(R.id.optGroup);
  btnCalendar = (RadioButton)findViewById(R.id.optCalendar);
  btnSpinners = (RadioButton)findViewById(R.id.optSpinners);
  btnBoth = (RadioButton)findViewById(R.id.optBoth);
  pickerDate = (DatePicker)findViewById(R.id.pickerdate);
  
  groupBtn.setOnCheckedChangeListener(new OnCheckedChangeListener(){

   @Override
   public void onCheckedChanged(RadioGroup arg0, int arg1) {
    if(btnCalendar.isChecked()){
     pickerDate.setCalendarViewShown(true);
     pickerDate.setSpinnersShown(false);
    }else if(btnSpinners.isChecked()){
     pickerDate.setCalendarViewShown(false);
     pickerDate.setSpinnersShown(true);
    }else{
     pickerDate.setCalendarViewShown(true);
     pickerDate.setSpinnersShown(true);
    }
   }});
 }

}