Saturday, June 14, 2014

[CodeIgniter] Remove the index.php in the URL and using sub folders for controller.

1. Edit .htacess file in www root folder.
This is what I have...

<IfModule mod_rewrite.c>
  Options +FollowSymLinks
  RewriteEngine On
  RewriteBase /
  # If your default controller is something other than 'welcome' you should probably change this.
  RewriteRule ^(welcome(/index)?|index(\.php)?)/?$ / [L,R=301]
  RewriteRule ^(.*)/index/?$ $1 [L,R=301]
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*)$ /index.php/$1 [L]
  SetEnvIfNoCase X-Forwarded-For .+ proxy=yes
  SetEnvIfNoCase X-moz prefetch no_access=yes
  
  # Block pre-fetch requests with X-moz headers.
  RewriteCond %{ENV:no_access} yes
  RewriteRule .* - [F,L]
  # Fix for infinite redirect loops.
  RewriteCond %{ENV:REDIRECT_STATUS} 200
  RewriteRule .* - [L]
</IfModule>

2. Make mod_rewrite enabled in apache configuration file(httpd.conf)
Just uncoment this line.
LoadModule rewrite_module modules/mod_rewrite.so

Make sure AllowOverride is set to All.
AllowOverride All

3. Extend the core Router class of CodeIgniter(for using controller sub folder)
You can obtain the MY_Router.php file at this link and save it to application/core/ folder.
https://degreesofzero.com/article/controllers-in-sub-sub-folders-in-codeigniter.html

4. Restart WAMP server.

5. Tips - If you want to add port based virtual hosts ....

Listen 8080
NameVirtualHost *:8080

<Directory />
#    Require all denied
    Options Indexes FollowSymLinks Includes ExecCGI
    AllowOverride All
    Order deny,allow
    Allow from all
</Directory>

<VirtualHost *:8080>
    ServerName localhost
    DocumentRoot "D:/admin"
</VirtualHost>



Monday, April 21, 2014

To do recursive works in Androd

1.  Create Notification service...

public class NotificationService extends Service{

public static boolean registered = false;

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

   Log.i("NotificationService", "Service Started!!!@@@@@@@@@@@@@@@@@@@@@@@");

   // TODO Add your jobs here

   return Service.START_STICKY; // .START_NOT_STICKY;
}

@Override

public IBinder onBind(Intent intent) {
     Log.i("NotificationService", "Service binded!!!@@@@@@@@@@@@@@@@@@@@@@@");
     // TODO Auto-generated method stub
     return null;
}

public static void startMe(final Context ctx, final long secs, boolean force){

     if(registered && !force) return;

     Log.i("NotificationService", "startMe!!!@@@@@@@@@@@@@@@@@@@@@@@");

     (new Thread(){

      public void run(){

       try {
          sleep(secs * 1000); // you can remove this code, if you don't want to have initial delay...
      } catch (InterruptedException e) {
      }

       Calendar cal = Calendar.getInstance();
      Intent intent = new Intent(ctx, NotificationService.class);
      PendingIntent pintent = PendingIntent.getService(ctx, 0, intent, 0);
      AlarmManager alarm = (AlarmManager)ctx.getSystemService(Context.ALARM_SERVICE);

       // Start every secs seconds
      alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), secs*1000, pintent);

       // alarm.cancel(operation);
      registered = true;
   }
}).start();
}
}

2. Update manifest xml.

<application

... >
....

<service android:name="com.examples.NotificationService"
android:enabled="true" />

3. Start service
In your activity or some where...

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_test);
   NotificationService.startMe(getBaseContext(), 30); // starts every 30 secs.
}

Google Cloud Messaging(GCM) for Android. (Part 2/2)

6. Implement GCM receiver code.(Client)
<< Broadcast Receiver class>>

public class GCMBroadcastReceiver extends WakefulBroadcastReceiver{
public static final String Key_Type = "Type";
public static final String Key_Command = "CMD";
public static final String Key_Msg = "MSG";

@Override
public void onReceive(Context context, Intent intent) {
    Log.i("GCMBroadcastReceiver.onReceive","new message is received.");


    Bundle extras = intent.getExtras();
    String action = intent.getAction();
    if(extras != null){
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
        String messageType = gcm.getMessageType(intent);
        // read data from gcm

        String type = intent.getStringExtra(Key_Type);
        String command = intent.getStringExtra(Key_Command);
        String msg = intent.getStringExtra(Key_Msg);

        // TODO you can add some specific code to do....
        // You can start new service to do some works.
        // startWakefulService(context, (intent.setComponent(comp)));
        // see the artical in google developer's guide http://developer.android.com/google/gcm/client.html#sample-receive

    }
}
}


7. Setup in AndroidManifast.xml file.(Client)
The instuction under ... http://developer.android.com/google/gcm/client.html#manifest

<manifest package="com.example.gcm" ...>
    <uses-permission android:name="android.permission.INTERNET" />

    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- I didn't add this permission -->
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

    <permission android:name="com.example.gcm.permission.C2D_MESSAGE"

android:protectionLevel="signature" />

    <uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" />


<application ...>
            <receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
                <intent-filter>
                    <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                    <category android:name="com.example.gcm" />
                </intent-filter>
            </receiver>
            <service android:name=".GcmIntentService" /> <!-- if you created service to handle gcm messages you should add this service-->
</application>


8. Implement GCM message sender.(Server)
  • This is the PHP function to send gcm message to GCM connecton server.
  • You can also send gcm message to GCM connection server from you android app.
  • As you may not need it if you have a server to send the message, I will not add the codes. :-)
  • I used Curl... and you can use the lib with comment off this extesion in php.ini, if you installed latest WAMP server.
  • extension=php_curl.dll

function sendGCMMessage_($data, $registrationIDs)
{   $apiKey = 'GsfgaSFc13-2reIDSD4qK_3_dfghspVWDSxEAA'; // this is the brower key you generated in 3. Creating a Google API project and obtaining an API Key.

    $senderId = "153023456724"; // this is the project code you generated in 3. Creating a Google API project and obtaining an API Key.

    $url = 'https://android.googleapis.com/gcm/send';

 

   $fields = array(

   'delay_while_idle' => False, // If you want to receive message when the phone is idle, you have to set this 'False'. You can set this 'True' to save the battery.
   'time_to_live' => 108,
   'collapse_key' => 'score_update',
   'registration_ids' => $registrationIDs,
   'data' => $data,

   );

   $headers = array(

   'Authorization: key=' . $apiKey,
   'Sender: id=' . $senderId,
   'Content-Type: application/json'

   );

   // Open connection
   $ch = curl_init();
   // Set the URL, number of POST vars, POST data

   curl_setopt( $ch, CURLOPT_URL, $url);

   curl_setopt( $ch, CURLOPT_POST, true);

   curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers);

   curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true);

   curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

   curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode( $fields));

   $result = curl_exec($ch);

   return $result;

}
  • how to call the function?? It is quite easy. 

$registrationIDs = array("APA91bEr6sdfjJzIsdfO76YsdfsvQ5NGago9JvRYod0v-n...", "APA91bEr6zWLWizsdfMO76YVRdfsfQ5NGagdfYod0vdsf...");
// The registeration id you obtained in 5. Implement GCM register code.(Client). You can add multiful registeration ids.

$data = array("Type" => "My Type", "CMD" => 'My Command', "MSG" => "My Message" );
// You should add the same key value pairs just the same as you will receive in you client app you implemented in 6. Implement GCM receiver code.(Client).
$result = sendGCMMessage_($data, $registrationIDs);
 

Sunday, April 20, 2014

Google Cloud Messaging(GCM) for Android. (Part 1/2)

1. What is GCM??

You can implement push service in you app with GCM and can find more information from this page.
This logo image is free to use.
http://developer.android.com/google/gcm/index.html

Under my experience, push messages cannot be delivered well when  user turn on wifi connection. So, you should implent pull service such as alarm notification together or develop your own push service.

The gcm message can be done under below messaging processes.

a. Register for GCM(Client)
This step only occurs on time for each client. In this step, client android app will obtain registration id from GCM connection server.
You can send the reg id to server to let server can send message to client with the key.

b. Send message to GCM connection server.(Server)
You have to implement a program to send message to GCM.
You will use the reg id of step 1.
I'll choose HTTP JSON method for this post.

c. GCM connection server tries to send message to client app.

d. Receive GCM message.(Client)
You have to implement WakefulBroadcastReceiver in your app.

2. Steps for implementation.
The step is quite simple.
  • Creating a Google API project and obtaining an API Key.
  • Set Up Google Play Services for Android.(Client)
  • Implement GCM register code.(Client)
  • Implement GCM receiver code.(Client)
  • Implement GCM message sender.(Server)
3. Creating a Google API project and obtaining an API Key.
  • go to google cloud console(https://cloud.google.com/console).
  • Create project if you don't have on yet. Copy project code to use later.
  • go to APIs & auth>Credentials and click 'Create New Key' button under Public API access.
  • In the Create a new key dialog, click Browser key.
  • When click 'create' button you can have a new browser key. Copy it to further use.
4. Set Up Google Play Services for Android.(Client)

Please see How to use Android Google Maps(API Ver2) in older Android version such as 2.3.(Part 1/2)  for this topic.
 
5. Implement GCM register code.(Client)
Your PROJECTCODE - the google API project code you created in 3. Creating a Google API project and obtaining an API Key.

@Override

protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_gcm_register);


   RegisterBackground task = new RegisterBackground();

   task.setContext(getBaseContext());

   task.execute();

}
// inner class that sends GCM registration request and receive registration id.
class RegisterBackground extends AsyncTask<String,String,String>{
   Context ctx;
   public void setContext(Context ctx){
      this.ctx = ctx;
   }
@Override

public String doInBackground(String... arg0) {
   String msg = "";
   String errMsg = "";
   try {
      String regId = GoogleCloudMessaging.getInstance(ctx).register("Your PROJECTCODE");
      msg = "Dvice registered, registration ID=" + regId;
      Log.i("GCMRegister.RegisterBackground", msg);
      if(regId != null){
         sendMyInfo(regId);
      }
   } catch (IOException ex) {
      errMsg = "Error :" + ex.getMessage();
      Log.e("GCMRegister.RegisterBackground", errMsg, ex);
   }
   return errMsg;
}
}
 
public void sendMyInfo(String regId){
    // TODO add your code to send GCM registration id to your server system.


Code igniter multiple file upload.

1. Prepare upload form view.

<< uploadview.php >>

<html>
<head>
<title>Upload Form</title>
</head>
<body>
<h2> file upload example </h2>
Only image files(gif|jpg|png) can be accepted. <br /> <br />
<?php echo $error;?>
<?php echo form_open_multipart('upload/do_upload');?>
<input type="file" name="userfile" size="20" /><br /><br />
<input type="file" name="userfile2" size="20" />
<br /><br />
<input type="submit" value="upload" />
</form>
</body>
</html>

2. Prepare uploadsuccess page view.

<< uploadsuccess.php >>

<html>
<head>
<title>Upload Form</title>
</head>
<body>
<h3>Your file was successfully uploaded!</h3>
<table ><tr valign=top><td>
<ul>
<?php foreach ($upload_data as $item => $value):?>
<li><?php echo $item;?>: <?php echo $value;?></li>
<?php endforeach; ?>
</ul>
<img src="/uploads/<?php echo $upload_data["file_name"]?>">
</td><td>
<ul>
<?php foreach ($upload_data2 as $item => $value):?>
<li><?php echo $item;?>: <?php echo $value;?></li>
<?php endforeach; ?>
</ul>
<img src="/uploads/<?php echo $upload_data2["file_name"]?>">
</td></tr></table>
<p><?php echo anchor('upload', 'Upload Another File!'); ?></p>
</body>
</html>

3. Prepare upload controller.

<< upload.php >>

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Upload extends CI_Controller {
    public function __construct() {
        parent::__construct();
    }

   function index()
   {
     $data['error'] = '';
     $this->load->view('uploadview', $data);
   }
   function do_upload()
   {
     $this->load->helper(array('form', 'url'));
     $config['upload_path'] = 'C:\wamp\www\uploads';
     $config['allowed_types'] = 'gif|jpg|png';
     $config['max_size'] = '100';
     $config['max_width']  = '1024';
     $config['max_height']  = '768';
     $this->load->library('upload', $config);

     $result = $this->upload->do_upload("userfile");
     if (!$result){
         $error = array('error' => $this->upload->display_errors());
         echo $this->upload->display_errors();
         $this->load->view('uploadview', $error);
         return;
     }
     $data = array('upload_data' => $this->upload->data());
     $result2 = $this->upload->do_upload("userfile2");
     if (!$result2){
         $error = array('error' => $this->upload->display_errors());
         echo $this->upload->display_errors();
         $this->load->view('uploadview', $error);
         return;
     }
     $data['upload_data2'] = $this->upload->data();
     $this->load->view('uploadsuccess', $data);
     }
}

4. You can find more information from this user-guide page.

http://ellislab.com/codeigniter/user-guide/libraries/file_uploading.html

Friday, April 11, 2014

How to use Android Google Maps(API Ver2) in older Android version such as 2.2.(Part 2/2)

1. Create new Android Application.
  • Go to File>New>Project.
  • Select Android>Android Application Project and click Next>.
  • Enter applciation name.
  • Enter package name. This should be the same package name you used when you created API key.
  • Select API 8: Android 2.2 (Froyo) in Minimu Required SDK.
  • Keep others as default and finish.
2. Load 'google-play-services_lib' to your project.(The same instructed in Part 1/2)
  • select Project>properties and go to Android.
  • In the Library box click 'Add...' button.
  • select 'google-play-services_lib' on the popup and click 'ok' button. 
 
3. Create New Activity and Layout.
  • Go to File>New>Others.
  • Select Android>Android Activity and click Next to the end.
  • Add google map fragment to your layout xml file.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
   <fragment
     android:id="@+id/gmap"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     class="com.google.android.gms.maps.SupportMapFragment"/>   
</LinearLayout>
 
4. Modify Actvity Class to handle google maps.
  • You may find some useful codes to control gmap. 
  • You can extends GMapActivity from FragmentActivty rather than ActionBarActivity.
package com.example.googlemaptest;
 
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
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.MarkerOptions;
 
public class GMapActivity extends ActionBarActivity {
private GoogleMap _gMap;
private int _mapType = GoogleMap.MAP_TYPE_NORMAL;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_gmap);
      Bundle extras = this.getIntent().getExtras();
      Location location = null;

      if (extras != null && extras.containsKey("GPSINFO")) {
           location = (Location)extras.get("GPSINFO");
      }
      FragmentManager fragmentManager = getSupportFragmentManager();
      SupportMapFragment mapFragment = (SupportMapFragment)
      fragmentManager.findFragmentById(R.id.gmap);
      _gMap = mapFragment.getMap();
      _gMap.getUiSettings().setCompassEnabled(true);
      _gMap.getUiSettings().setZoomControlsEnabled(true);
      _gMap.getUiSettings().setMyLocationButtonEnabled(true);
      _gMap.getUiSettings().setAllGesturesEnabled(true);
      _gMap.getUiSettings().setMyLocationButtonEnabled(true);
      _gMap.getUiSettings().setRotateGesturesEnabled(true);
      _gMap.getUiSettings().setTiltGesturesEnabled(true);
      _gMap.getUiSettings().setZoomGesturesEnabled(true);
      _gMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);

      LatLng sfLatLng = null;
      if(location != null){
      double lat = location.getLatitude();
      double lng = location.getLongitude();
      sfLatLng = new LatLng(lat, lng);
      Geocoder geocoder = new Geocoder(this, Locale.getDefault());
      List<Address> addresses = null;
      try {
      addresses = geocoder.getFromLocation(lat, lng, 1);
      } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }
      if(addresses != null){
      _gMap.addMarker(new MarkerOptions()
      .position(sfLatLng)
      .title("Position in " + addresses.get(0).getAddressLine(1) + " " + addresses.get(0).getAddressLine(2))
      .snippet(addresses.get(0).getAddressLine(0))
      .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)));
      }else{
      _gMap.addMarker(new MarkerOptions()
      .position(sfLatLng)
      .title("Position")
      .snippet("No address is available")
      .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))); 
      }
      _gMap.animateCamera(CameraUpdateFactory.newLatLngZoom(sfLatLng, 13));
      }else{
      }
   }

5. Change Manifast file.

  • add uses-feature.
  • add premission.
  • add meta-data for API key.
  • add meta-data for gms version.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.example.googlemaptest"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
 

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

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

<application
        ...  >
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="AIASDFASlSG6qfsadfdfZtZVnuZTJyfsSDFSD2" />
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
 
6. Call GMapActivity
  • You can add this code  to call GMapActvity. 
Location location = new Location("You are here");
location.setLatitude(latitude);
location.setLongitude(longitude);

Intent intent = new Intent(getBaseContext(), GMapActivity.class);
intent.putExtra("GPSINFO", location);
startActivity(intent);  

  • In some older verion android phone google play service should be updated.
  • In the case of content filtering message, go to Menu>Settings in Google Play Store and unlock Content Filtering in User Controls.