Thursday, August 1, 2013

Display Custom Info Window with ImageView on Google Map V2

Display Custom Info Window with ImageView on Google Map V2

 


To display image on Google Map V2 Bubble, we will be integrating Universal Image Loader
In Map V2, to display custom bubble, there is a InfoWindowAdapter class.

Implement the InfoWindowAdapter class and override 2 methods :
1. getInfoContents(Marker marker)
2. getInfoWindow(Marker marker)

Set InfoWindowAdapter
googleMap.setInfoWindowAdapter(new CustomInfoWindowAdapter());
Store Marker id in variable with each marker image URL. So, in CustomInfoWindowAdapter class, it can be accessed using Marker Id. Fro now we will store id in Hashtable:
markers.put(hamburg.getId(), "http://img.india-forums.com/images/100x100/37525-a-still-image-of-akshay-kumar.jpg");
Create custom_info_window.xml layout. It will be displayed when click on Marker.
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/custom_info_bubble"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/badge"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginRight="5dp"
        android:adjustViewBounds="true" >
    </ImageView>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:singleLine="true"
            android:textColor="#ff000000"
            android:textSize="14dp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/snippet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#ff7f7f7f"
            android:textSize="14dp" />
    </LinearLayout>

</LinearLayout>

CustomInfoWindowAdapter 

package com.ngshah.goglemapv2withlazyloading;

import java.util.Hashtable;

import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.ngshah.goglemapv2withlazyloading.R;
import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
import com.nostra13.universalimageloader.cache.memory.impl.FIFOLimitedMemoryCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.core.assist.SimpleImageLoadingListener;

public class MainActivity extends FragmentActivity {

    private GoogleMap googleMap;
    private final LatLng HAMBURG = new LatLng(53.558, 9.927);
    private final LatLng KIEL = new LatLng(53.551, 9.993);
    private Marker marker;
    private Hashtable<String, String> markers;
    private ImageLoader imageLoader;
    private DisplayImageOptions options;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        googleMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
                .getMap();
        
        initImageLoader();
        markers = new Hashtable<String, String>();
        imageLoader = ImageLoader.getInstance();
        
        options = new DisplayImageOptions.Builder()
            .showStubImage(R.drawable.ic_launcher)        //    Display Stub Image
            .showImageForEmptyUri(R.drawable.ic_launcher)    //    If Empty image found
            .cacheInMemory()
            .cacheOnDisc().bitmapConfig(Bitmap.Config.RGB_565).build();
        
        if ( googleMap != null ) {
           
            googleMap.setInfoWindowAdapter(new CustomInfoWindowAdapter());
           
            final Marker hamburg = googleMap.addMarker(new MarkerOptions().position(HAMBURG)
                        .title("Hamburg"));
            markers.put(hamburg.getId(), "http://img.india-forums.com/images/100x100/37525-a-still-image-of-akshay-kumar.jpg");
           
            final Marker kiel = googleMap.addMarker(new MarkerOptions()
                        .position(KIEL)
                        .title("Kiel")
                        .snippet("Kiel is cool")
                        .icon(BitmapDescriptorFactory
                            .fromResource(R.drawable.ic_launcher)));
            markers.put(kiel.getId(), "http://www.yodot.com/images/jpeg-images-sm.png");
             
            googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(HAMBURG, 15));
            googleMap.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);
        }
    }
    
    private class CustomInfoWindowAdapter implements InfoWindowAdapter {

        private View view;

        public CustomInfoWindowAdapter() {
            view = getLayoutInflater().inflate(R.layout.custom_info_window,
                    null);
        }

        @Override
        public View getInfoContents(Marker marker) {

            if (MainActivity.this.marker != null
                    && MainActivity.this.marker.isInfoWindowShown()) {
                MainActivity.this.marker.hideInfoWindow();
                MainActivity.this.marker.showInfoWindow();
            }
            return null;
        }

        @Override
        public View getInfoWindow(final Marker marker) {
            MainActivity.this.marker = marker;

            String url = null;

            if (marker.getId() != null && markers != null && markers.size() > 0) {
                if ( markers.get(marker.getId()) != null &&
                        markers.get(marker.getId()) != null) {
                    url = markers.get(marker.getId());
                }
            }
            final ImageView image = ((ImageView) view.findViewById(R.id.badge));

            if (url != null && !url.equalsIgnoreCase("null")
                    && !url.equalsIgnoreCase("")) {
                imageLoader.displayImage(url, image, options,
                        new SimpleImageLoadingListener() {
                            @Override
                            public void onLoadingComplete(String imageUri,
                                    View view, Bitmap loadedImage) {
                                super.onLoadingComplete(imageUri, view,
                                        loadedImage);
                                getInfoContents(marker);
                            }
                        });
            } else {
                image.setImageResource(R.drawable.ic_launcher);
            }

            final String title = marker.getTitle();
            final TextView titleUi = ((TextView) view.findViewById(R.id.title));
            if (title != null) {
                titleUi.setText(title);
            } else {
                titleUi.setText("");
            }

            final String snippet = marker.getSnippet();
            final TextView snippetUi = ((TextView) view
                    .findViewById(R.id.snippet));
            if (snippet != null) {
                snippetUi.setText(snippet);
            } else {
                snippetUi.setText("");
            }

            return view;
        }
    }

    private void initImageLoader() {
        int memoryCacheSize;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) {
            int memClass = ((ActivityManager) 
                    getSystemService(Context.ACTIVITY_SERVICE))
                    .getMemoryClass();
            memoryCacheSize = (memClass / 8) * 1024 * 1024;
        } else {
            memoryCacheSize = 2 * 1024 * 1024;
        }

        final ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
                this).threadPoolSize(5)
                .threadPriority(Thread.NORM_PRIORITY - 2)
                .memoryCacheSize(memoryCacheSize)
                .memoryCache(new FIFOLimitedMemoryCache(memoryCacheSize-1000000))
                .denyCacheImageMultipleSizesInMemory()
                .discCacheFileNameGenerator(new Md5FileNameGenerator())
                .tasksProcessingOrder(QueueProcessingType.LIFO).enableLogging() 
                .build();

        ImageLoader.getInstance().init(config);
    }
} 
Read More

Wednesday, July 31, 2013

Android Google Map V2




To use the Google Maps Android API v2 in your app, you will first need to install the Google Play services SDK.

Install Google Play Service

Open Android SDK Manager and install Google Play services from Extras


Obtain Google Map V2 Key

Generate SHA-1 key of debug.keystore or application sign keystore.

Debug keystore can be found at <userhome/.android/debug.keystore>

To generate SHA-1 of debug keystore use below command :
keytool -list -v -keystore <debug keystore path>/debug.keystore -alias androiddebugkey -storepass android -keypass android

To access the Google Maps with the Maps API, you have to add a Maps API key to your application. You can get this key via Google API Console .

Create your project in Google API Console



Create new Android Key


Enter your SHA-1 key;your application package name


Use API key in your manifest file.



Activate Google Maps Android API v2 from Services

Example :

Import Google play Services library into your workspace.

Import from <android sdk>/extras/google/google_play_services/libproject/google-play-services_lib

Create your project
Add Google Play Service library into your Project.

In your project Manifest file, include below code :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.ngshah.googlemapv2"
    android:versionCode="1"
    android:versionName="1.0" >

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

    <permission
        android:name="com.ngshah.googlemapv2.permission.MAPS_RECEIVE"
        android:protectionLevel="signature" />

    <uses-permission android:name="com.ngshah.googlemapv2.permission.MAPS_RECEIVE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="your_api_key" />

        <activity
            android:name="com.ngshah.googlemapv2.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>
Change your api key.
<uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />

android:glEsVersion="0x00020000" means its supports only OpenGL ES version 2 devices. And this tag should be included in your Manifest file. 
In your xml file write below fragment.
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    class="com.google.android.gms.maps.SupportMapFragment" />

Add Marker on Map

package com.ngshah.googlemapv2;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

public class MainActivity extends FragmentActivity {
    
    private GoogleMap googleMap;
    private final LatLng HAMBURG = new LatLng(53.558, 9.927);
    private final LatLng KIEL = new LatLng(53.551, 9.993);
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        googleMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
                .getMap();
        
        if ( googleMap != null ) {
              Marker hamburg = googleMap.addMarker(new MarkerOptions().position(HAMBURG)
                        .title("Hamburg"));
              Marker kiel = googleMap.addMarker(new MarkerOptions()
                        .position(KIEL)
                        .title("Kiel")
                        .snippet("Kiel is cool")
                        .icon(BitmapDescriptorFactory
                            .fromResource(R.drawable.ic_launcher)));

              googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(HAMBURG, 15));
              googleMap.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);
        }
    }
}

Download full Source Code
Read More

Monday, November 21, 2011

Android Google Map Example


Obtain a map key
keytool -list -alias androiddebugkey -keystore /Volumes/MAC\ OS/Users/name/.android/debug.keystore -storepass android -keypass android

Copy Certificate fingerprint (MD5) and paste it. Android Maps API Key Signup
Read More

Thursday, October 20, 2011

Custom ListView with CheckBox

Hi, Layout: main.xml
<Relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <Button
        android:id="@+id/main_btn_data"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignparentbottom="true"
        android:layout_alignparentleft="true"
        android:onclick="onClickData"
        android:text="@string/hello" />
    <Listview
        android:id="@+id/listView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/main_btn_data"
        android:layout_alignparentleft="true"
        android:layout_alignparenttop="true" />
</Relativelayout>

<Relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <Textview
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignbaseline="@+id/checkBox1"
        android:layout_alignbottom="@+id/checkBox1"
        android:layout_alignparentleft="true"
        android:text="TextView"
        android:textappearance="?android:attr/textAppearanceLarge" />

    <Checkbox
        android:id="@+id/checkBox1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignparentright="true"
        android:layout_alignparenttop="true" />

</Relativelayout>


MultipleCheckerActivity.java
public class MultipleCheckerActivity extends Activity {
 
 private ListView list;
 private List employee;
 private EmployeeAdapter adapter;
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        employee = new ArrayList();
        fillData("Nishant", "Shah", 25, false);
        fillData("Chirag", "Shah", 22, false);
        fillData("Utsav", "Kapuriya", 22, false);
        
        list = (ListView) findViewById(R.id.listView1);
        adapter = new EmployeeAdapter(getApplicationContext(), R.layout.row_main, employee);
        list.setAdapter(adapter);
    }
    
    private void fillData ( String name, String lastName, int age, boolean isSelected ) {
     final EmployeeModel model = new EmployeeModel();
     model.setName(name);
     model.setLastName(lastName);
     model.setAge(age);
     model.setSelected(isSelected);
     
     employee.add(model);
    }
    
    public void onClickData ( View view ) {
     List empData = adapter.employeeData;
     System.out.println("Total Size :"  + empData.size());
     
     for (EmployeeModel employeeModel : empData) {
   if ( employeeModel.isSelected() ) {
    Log.e("Checker", employeeModel.getName());
   }
  }
    }
}


EmployeeAdapter.java
public class EmployeeAdapter extends BaseAdapter {
 
 public List employeeData;
 private Context mContext;
 private LayoutInflater mInflater;
 
 public EmployeeAdapter(Context context, int textViewResourceId,
   List objects) {
  this.employeeData = objects;
  this.mContext = context;
  mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 }
 
 public View getView(int position, View convertView, ViewGroup parent) {
  ViewHolder holder;
  
  if (convertView == null) {
   holder = new ViewHolder();
   
   convertView = mInflater.inflate(R.layout.row_main, null);
   
   holder.txtName = (TextView) convertView.findViewById(R.id.textView1);
   holder.chkTick = (CheckBox) convertView.findViewById(R.id.checkBox1);
   
   convertView.setTag(holder);
  } else {
   holder = (ViewHolder) convertView.getTag();
  }
  
  final int pos = position;
  holder.txtName.setText(employeeData.get(position).getName() + " " + 
    employeeData.get(position).getLastName());
  holder.chkTick.setOnCheckedChangeListener(new OnCheckedChangeListener() {
   public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    employeeData.get(pos).setSelected(isChecked);
   }
  });
  
  return convertView;
 }
 
 static class ViewHolder {
  TextView txtName;
  CheckBox chkTick;
 }

 public int getCount() {
  return employeeData.size();
 }

 public EmployeeModel getItem(int position) {
  return employeeData.get(position);
 }

 public long getItemId(int position) {
  return 0;
 }
}


EmployeeModel.java
public class EmployeeModel {

 private String name;
 private int age;
 private String lastName;
 private boolean selected;

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public int getAge() {
  return age;
 }

 public void setAge(int age) {
  this.age = age;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

 public boolean isSelected() {
  return selected;
 }

 public void setSelected(boolean selected) {
  this.selected = selected;
 }
}

Read More

Tuesday, September 6, 2011

Android MediaRecorder Example


The android.media package contains classes to interact with the media subsystem. The android.media.MediaRecorder class is used to take samples of media, including audio and video. The MediaRecorder operates as a state machine. You need to set various parameters, such as source device and format. Once set, the recording may begin for an arbitrary amount of time until subsequently stopped.
The code shown does not include the UI elements of the application (see download for the full source code).
MediaRecorder mrec ;
File audiofile = null;
private static final String TAG="SoundRecordingDemo";
protected void startRecording() throws IOException 
{
   mrec.setAudioSource(MediaRecorder.AudioSource.MIC);
   mrec.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
   mrec.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
   if (mSampleFile == null) 
   {
       File sampleDir = Environment.getExternalStorageDirectory();
       try 
       { 
          audiofile = File.createTempFile("ibm", ".3gp", sampleDir);
       }
       catch (IOException e) 
       {
           Log.e(TAG,"sdcard access error");
           return;
       }
   }
   mrec.setOutputFile(audiofile.getAbsolutePath());
   mrec.prepare();
   mrec.start();
}
protected void stopRecording() 
{
   mrec.stop();
   mrec.release();
   processaudiofile(audiofile.getAbsolutePath());
}
protected void processaudiofile() 
{
   ContentValues values = new ContentValues(3);
   long current = System.currentTimeMillis();
   values.put(MediaStore.Audio.Media.TITLE, "audio" + audiofile.getName());
   values.put(MediaStore.Audio.Media.DATE_ADDED, (int) (current / 1000));
   values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/3gpp");
   values.put(MediaStore.Audio.Media.DATA, audiofile.getAbsolutePath());
   ContentResolver contentResolver = getContentResolver();
   
   Uri base = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
   Uri newUri = contentResolver.insert(base, values);
   
   sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, newUri));
}

In the startRecording method, an instance of a MediaRecorder is instantiated and initialized:
  • The input source is set to the microphone (MIC).
  • The output format is set to 3GPP (*.3gp files), which is a media format geared toward mobile devices.
  • The encoder is set to the AMR_NB, which is an audio format, sampling at 8 KHz. The NB is for narrow band
The audio file is stored on the storage card, rather than in internal memory. External.getExternalStorageDirectory()returns the name of the storage card location, and a temporary file name is created in that directory. This file is then associated with the MediaRecorder instance by a call to the setOutputFile method. The audio data will be stored in this file.
The prepare method is invoked to finalize the initialization of the MediaRecorder. When you're ready to commence the recording process, the start method is called. Recording takes place to the file on the storage card until the stop method is invoked. The release method frees resources allocated to the MediaRecorder instance.
Once the audio sample has been taken, there are a few actions that can take place:
  • Add the audio to the media library on the device.
  • Perform some pattern recognition steps to identify the sound:
    • Is this the baby crying?
    • Is this the owner's voice, and should we unlock the phone?
    • Is this the "open-sesame" phrase that unlocks the door to the secret entrance?
  • Automatically upload the audio file to a network location for processing.
In the code sample, the processaudiofile method adds the audio to the media library. An Intent is used to notify the on-device media application that new content is available.
One final note about this snippet of code: If you try it, it won't record the audio at first. You will see a file created, but there will be no audio. You need to add a permission to the AndroidManifest.xml file:
<uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>

At this point, you've learned a bit about interacting with Android sensors and recording audio. The next section takes a broader view of application architecture related to data gathering and reporting systems.

Read More

Monday, September 5, 2011

Gradient dividers in Android

Many of Android’s screens use attractive dividers with gradients that fade from black to white to black.  Here’s how to create one of your own.


  

2. Create a view in the target layout and apply the gradient as the background.  The “black_white_gradient” in “@drawable/black_white_gradient” refers to the file name of the shape above.
<View android:id="@+id/divider"
    android:background="@drawable/black_white_gradient"
    android:layout_width="fill_parent"
    android:layout_height="1dp"
    android:layout_below="@id/someOtherThing" />
Read More

Update Android Gallery

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
Read More