Pages

Android: checking IP of your devie





$ adb shell netcfg
lo       UP                                   127.0.0.1/8   0x00000049 00:00:00:00:00:00
can0     UP                                     0.0.0.0/0   0x000000c1 00:00:00:00:00:00
can1     UP                                     0.0.0.0/0   0x000000c1 00:00:00:00:00:00
can2     UP                                     0.0.0.0/0   0x000000c1 00:00:00:00:00:00
can3     UP                                     0.0.0.0/0   0x000000c1 00:00:00:00:00:00
tunl0    DOWN                                   0.0.0.0/0   0x00000080 00:00:00:00:00:00
sit0     DOWN                                   0.0.0.0/0   0x00000080 00:00:00:00:00:00
ip6tnl0  DOWN                                   0.0.0.0/0   0x00000080 00:00:00:00:00:00

eth0     UP                                 192.168.1.4/24  0x00001043 00:04:a3:92:d4:0b

If you like this post, please give me your 2 cents ($0.02 litterally) to show token of appreciation and encourage me to write more:

Donate Bitcoins



Android: start app on reboot

In this tutorial we will learn how to start an app (Activity or Service) on Android reboot.



Step: Android manifest

        <receiver
                android:name=".BootBroadcastReceiver"
                android:enabled="true"
                android:exported="true"
                android:label="Start SMS on boot">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

    </application>

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



Step: BroadcastReceiver

package com.chicagoandroid.android.app.sms;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/**
 * Created by uki on 11/22/14.
 */
public class BootBroadcastReceiver extends BroadcastReceiver {
   @Override
   public void onReceive(Context context, Intent intent) {
      if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
         Intent serviceIntent = new Intent(context, MainActivity.class);
         context.startService(serviceIntent);
      }
   }
}



Android: detect your own phone number

In this tutorial you will learn how to detect your own phone number programmatically



Step: add permission to Android Manifest

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



Step: use TelephonyManager to read the number

   private String getMyPhoneNumber() {
      TelephonyManager manager = (TelephonyManager) appContext.getSystemService(Context.TELEPHONY_SERVICE);
      String myPhoneNumber = manager.getLine1Number();
      return myPhoneNumber;
   }






Android: send SMS programmatically

This tutorial is a continuation of previous post:
http://ukitech.blogspot.com/2014/11/android-calling-activity-from.html

We will learn how to SENT a SMS programmatically.


Step: Improve UI





<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:paddingLeft="@dimen/activity_horizontal_margin"
              android:paddingRight="@dimen/activity_horizontal_margin"
              android:paddingTop="@dimen/activity_vertical_margin"
              android:paddingBottom="@dimen/activity_vertical_margin"
              android:orientation="vertical"
              tools:context=".MainActivity">
    <TextView
            android:text="If SMS starts with.. "
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    <EditText
            android:id="@+id/sms_search_text"
            android:layout_marginLeft="32dp"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:hint="CIT299?"/>

    <TextView
            android:text="Respond with the SMS message.."
            android:layout_marginTop="16dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    <EditText
            android:id="@+id/sms_respond_text"
            android:layout_marginLeft="32dp"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:hint="finish this app, study hard, prepare the final"/>

    <TextView
            android:text="Received SMS.."
            android:layout_marginTop="16dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    <ScrollView
            android:layout_width="fill_parent"
            android:layout_height="100dp">
        <TextView
                android:id="@+id/sms_received"
                android:layout_marginLeft="32dp"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:hint="1\n2\n3\n4\n5\n6\n7\n8\n9\n"/>
    </ScrollView>
</LinearLayout>










Step: new class SmsSender.java


package com.chicagoandroid.android.app.sms;
import android.app.PendingIntent;
import android.content.Context;
import android.telephony.PhoneNumberUtils;
import android.telephony.SmsManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
/**
 * Created by uki on 11/22/14.
 */
public class SmsSender {
   private static final String TAG = SmsSender.class.getSimpleName();
   Context appContext;
   public SmsSender(Context context) {
      appContext = context;
   }
   public void send(String destinationAddress, String text) {
      if (!PhoneNumberUtils.isWellFormedSmsAddress(destinationAddress)) {
         Log.e(TAG, "SMS number is malformed");
         return;
      }
      SmsManager smsManager = SmsManager.getDefault();
      String scAddress = null; //getMyPhoneNumber();
      PendingIntent sentIntent = null;
      PendingIntent deliveryIntent = null; // broadcast when delivered
      try {
         smsManager.sendTextMessage(destinationAddress, scAddress, text, sentIntent, deliveryIntent);
         Log.w(TAG, "message sent: " + text + " to " + destinationAddress);
      }
      catch (Exception e) {
         Log.e(TAG, "SMS not sent: " + e.getMessage());
         //TODO handle
      }
   }




Step: Send message from SmsParser

   public void processReceivedSms(String smsOriginatingAddress, String smsDisplayMessage) {
      final String tag = TAG + ".processReceivedSms";
      Log.i(tag, "SMS from  " + smsOriginatingAddress);
      Log.i(tag, "SMS body  " + smsDisplayMessage);
      mainActivity.appendSmsToUI("SMS from  " + smsOriginatingAddress + "\n" + smsDisplayMessage);
      String keyword = mainActivity.getSmsTextSearch();
      if (doesSmsStartWith(smsDisplayMessage, keyword)) {
         Log.i(tag, "SMS does start with " + keyword);
         String responseText = mainActivity.getSmsRespondSearch();
         Log.i(tag, "Attempting to respond: " + responseText);
         SmsSender sender = new SmsSender(appContext);
         sender.send(smsOriginatingAddress, responseText);

      }
      else
         Log.e(TAG + ".onReceive", "SMS does not start with " + keyword);
   }



Step: MainActivity - full listing

package com.chicagoandroid.android.app.sms;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity {
   private EditText etSmsTextSearch, etSmsRespondSearch;
   private TextView smsReceived;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      etSmsTextSearch = (EditText) findViewById(R.id.sms_search_text);
      etSmsRespondSearch = (EditText) findViewById(R.id.sms_respond_text);
      smsReceived = (TextView) findViewById(R.id.sms_received);
      // keep reference to Activity context
      MyApplication myApplication = (MyApplication) this.getApplicationContext();
      myApplication.mainActivity = this;
   }
   public String getSmsTextSearch() {
      String text = etSmsTextSearch.getText().toString();
      //todo save to preferences
      if (text == null || text.equalsIgnoreCase("")) text = "Not Provided";
      return text;
   }
   public String getSmsRespondSearch() {
      String text = etSmsRespondSearch.getText().toString();
      //todo save to preferences
      if (text == null || text.equalsIgnoreCase("")) text = "Not Provided";
      return text;
   }
   public void appendSmsToUI(String text) {
      smsReceived.append(text + "\n");
   }
   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.main, menu);
      return true;
   }
   @Override
   public boolean onOptionsItemSelected(MenuItem item) {
      // Handle action bar item clicks here. The action bar will
      // automatically handle clicks on the Home/Up button, so long
      // as you specify a parent activity in AndroidManifest.xml.
      int id = item.getItemId();
      if (id == R.id.action_settings) {
         return true;
      }
      return super.onOptionsItemSelected(item);
   }
}




Android: calling Activity from BroadcastReceiver

This tutorial is a continuation of the previous post:
http://ukitech.blogspot.com/2014/11/android-sms-app.html

We will learn how to connect Activity (UI) and BroadcastReceiver which does not know the Activity (and hence the UI) using Application class.



Step: create Application class

package com.chicagoandroid.android.app.sms;
import android.app.Application;
/**
 * Created by uki on 11/22/14.
 */
public class MyApplication extends Application {
   @Override
   public void onCreate() {
      super.onCreate();
   }
   /**
    * we use this class member to hold instance of our activity.
    */
   public MainActivity mainActivity;
}


Step: Declare it in the AndroidManifest.xml file

    <application
            android:name="com.chicagoandroid.android.app.sms.MyApplication"

Step: Pass Activity to Application

public class MainActivity extends ActionBarActivity {
...
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      etSmsTextSearch = (EditText) findViewById(R.id.sms_search_text);
      etSmsRespondSearch = (EditText) findViewById(R.id.sms_respond_text);
      smsReceived = (TextView) findViewById(R.id.sms_received);
      // keep reference to Activity context
      MyApplication myApplication = (MyApplication) this.getApplicationContext();
      myApplication.mainActivity = this;

   }


Step: In your BroadcastReceiver make sure you use Application Context

   @Override
   public void onReceive(Context context, Intent intent) {
      ...
         parser = new SmsParser(context);


Step: From Application Context get the Activity

   public SmsParser(Context context) {
      mainActivity = ((MyApplication) context.getApplicationContext()).mainActivity;
   }



Step: Form Activity you can call PUBLIC methods.

      String keyword = mainActivity.getSmsTextSearch();



Android Studio: GIT: .gitignore

Managing which files should be ignored by GIT (code repository) it an important skill. It is done by .gitignore file in which each line represents a directory, a pattern, or a file to be ignored.


Step: Stay organized


Keep your GIT ignore file organized, I keep it ordered alphabetically using a script in TextWrangler editor.

Step: Find Plugin

Always investigate plugins available to support your code.





Android: SMS app: receiving

In this tutorial we will learn how to handle incoming messages, how to parse them to find a pattern, and how to send an SMS.

Step: As always update to newest version of your IDE and tools (SDK manager)


Step: Create a new Android app module.




Step: Select cool icon for your SMS app



Step: Select Blank Activity


Step: Name your MainActivity




Step: Add PERMISSIONS

Step: Add receiver class declaration

Step: Add intent-filter for SMS_RECEIVED


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.chicagoandroid.android.app.sms">
    <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme">
        <activity
                android:name=".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>
        <receiver android:name=".SmsReceiver">
            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
            </intent-filter>
        </receiver>


    </application>

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

</manifest>

Step: Create a new class SmsReceiver

package com.chicagoandroid.android.app.sms;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.provider.Telephony;
import android.telephony.SmsMessage;
import android.util.Log;
//deprecated import android.telephony.gsm.SmsMessage;
/**
 * Created by uki on 11/22/14.
 */
public class SmsReceiver extends BroadcastReceiver {
      private static final String TAG = SmsReceiver.class.getSimpleName();
      private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
      @Override
      public void onReceive(Context context, Intent intent) {
            final String tag = TAG + ".onReceive";
            Bundle bundle = intent.getExtras();
            if (bundle == null) {
                  Log.w(tag, "BroadcastReceiver failed, no intent data to process.");
                  return;
            }
            if (intent.getAction().equals(SMS_RECEIVED)) {
                  Log.d(tag, "SMS_RECEIVED");
                  String smsOriginatingAddress, smsDisplayMessage;
                  /**
                   * You have to CHOOSE which code snippet to use NEW (KitKat+), or legacy
                   * Please comment out the for{} you don't want to use.
                   */
                  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                        Log.d(tag, "KitKat or newer + API " + Build.VERSION.SDK_INT);
                        // API level 19 (KitKat 4.4) getMessagesFromIntent
                        for (SmsMessage message : Telephony.Sms.Intents.getMessagesFromIntent(intent)) {
                              if (message == null) {
                                    Log.e(tag, "SMS message is null -- ABORT");
                                    break;
                              }
                              smsOriginatingAddress = message.getDisplayOriginatingAddress();
                              smsDisplayMessage = message.getDisplayMessageBody(); //see getMessageBody();
                              SmsParser.processReceivedSms(smsOriginatingAddress, smsDisplayMessage);
                        }
                  }
                  else { // BELOW KITKAT
                        Log.d(tag, "legacy SMS implementation (before KitKat) API " + Build.VERSION.SDK_INT);
                        // Processing SMS messages the OLD way, before KitKat, this WILL work on KitKat or newer Android
                        // PDU is a “protocol data unit”, which is the industry format for an SMS message
                        Object[] data = (Object[]) bundle.get("pdus");
                        for (Object pdu : data) {
                              SmsMessage message = SmsMessage.createFromPdu((byte[]) pdu);
                              if (message == null) {
                                    Log.e(tag, "SMS message is null -- ABORT");
                                    break;
                              }
                              smsOriginatingAddress = message.getDisplayOriginatingAddress();
                              smsDisplayMessage = message.getDisplayMessageBody(); // see getMessageBody();
                              SmsParser.processReceivedSms(smsOriginatingAddress, smsDisplayMessage);
                        }
                  }
            } // onReceive method
      }
}





StockOverflow: http://stackoverflow.com/a/27076215/3566154

Step: Simple SMS parser

package com.chicagoandroid.android.app.sms;

import android.util.Log;

/**
 * Created by uki on 11/22/14.
 */
public class SmsParser {
   private static final String TAG = SmsParser.class.getSimpleName();
   public static void processReceivedSms(String smsOriginatingAddress, String smsDisplayMessage) {
      final String tag = TAG + ".processReceivedSms";
      Log.i(tag, "SMS from  " + smsOriginatingAddress);
      Log.i(tag, "SMS body  " + smsDisplayMessage);
      String keyword = "Info?";
      if (doesSmsStartWith(smsDisplayMessage, keyword)) {
         Log.i(tag, "SMS does start with " + keyword);
      }
      else
         Log.e(TAG + ".onReceive", "SMS does not start with " + keyword);
   }
   /**
    * this is a very simple method to detect if
    * the SMS message starts with a given character sequence
    */
   private static boolean doesSmsStartWith(String smsMessage, String txt) {
      return smsMessage.trim().toLowerCase().startsWith(txt.trim().toLowerCase());
   }
}


Step: run this app and test receiving SMS in LogCat


11-22 04:55:13.783  10317-10317/com.chicagoandroid.android.app.sms D/SmsReceiver.onReceive﹕ SMS_RECEIVED
11-22 04:55:13.803  10317-10317/com.chicagoandroid.android.app.sms D/SmsReceiver.onReceive﹕ KitKat or newer
11-22 04:55:13.803  10317-10317/com.chicagoandroid.android.app.sms I/SmsParser.processReceivedSms﹕ SMS from  +1650815xxxx // privacy
11-22 04:55:13.803  10317-10317/com.chicagoandroid.android.app.sms I/SmsParser.processReceivedSms﹕ SMS body  Test 6
11-22 04:55:13.803  10317-10317/com.chicagoandroid.android.app.sms E/SmsParser.onReceive﹕ SMS does not start with Info?
11-22 04:55:13.803  10317-10317/com.chicagoandroid.android.app.sms D/SmsReceiver.onReceive﹕ legacy SMS implementation (before KitKat)
11-22 04:55:13.803  10317-10317/com.chicagoandroid.android.app.sms I/SmsParser.processReceivedSms﹕ SMS from  +16508156603
11-22 04:55:13.803  10317-10317/com.chicagoandroid.android.app.sms I/SmsParser.processReceivedSms﹕ SMS body  Test 6
11-22 04:55:13.803  10317-10317/com.chicagoandroid.android.app.sms E/SmsParser.onReceive﹕ SMS does not start with Info?

Step: create basic UI






android-maven-plugin-4.0

As you are migrating your projects from old to new Android structure you may encounter:




[ERROR] Found files or folders in non-standard locations in the project! [ERROR] ....This might be a side-effect of a migration to Android Maven Plugin 4+.

android-maven-plugin-4.0 uses the new Android Studio folder layout which is much more Mavenish.

  • Android resources should be is src\main\res, 
  • Android assets in src\main\assets, 
  • AndroidManifest.xml in src\main


Mac OS X Yosemite: Java and Android developer

If you did not upgrade yet, you will probably do so within days, here are my observations so far.




Java 

When you upgrade to Yosemite your previous Java is still there:

$ java -version
java version "1.8.0_20-ea"
Java(TM) SE Runtime Environment (build 1.8.0_20-ea-b05)

Java HotSpot(TM) 64-Bit Server VM (build 25.20-b05, mixed mode)

but Apple open dialogs that you have to install older Java, I am probably missing a symbolic link from what the default installation should be.

Java 1.6 from Apple:
http://support.apple.com/kb/DL1572


IntelliJ IDEA


The software says my Android SDK is missing.





12a. Android: JSON OpenWeatherMap

In this tutorial we will implement basic weather OpenWeatherMap API using JSON (JavaScript Object Notation).
links:

API information:
http://openweathermap.org/api

JSON:
http://api.openweathermap.org/data/2.5/weather?q=Mundelein,IL

Image URL:
http://openweathermap.org/img/w/10d.png

JSON (pretty) formatter in TextWrangler editor (Mac)
http://ukitech.blogspot.com/2012/08/format-json-in-free-textwrangler.html

Example JSON data:

http://api.openweathermap.org/data/2.5/weather?q=Mundelein,IL
http://openweathermap.org/img/w/10d.png

{
  "base": "cmc stations",
  "clouds": {
    "all": 1
  },
  "cod": 200,
  "coord": {
    "lat": 42.27,
    "lon": -88
  },
  "dt": 1416040500,
  "id": 4903184,
  "main": {
    "humidity": 92,
    "pressure": 1027,
    "temp": 265.36,
    "temp_max": 268.15,
    "temp_min": 261.15
  },
  "name": "Mundelein",
  "sys": {
    "country": "United States of America",
    "id": 2981,
    "message": 0.0294,
    "sunrise": 1416055401,
    "sunset": 1416090602,
    "type": 1
  },
  "weather": [
    {
      "description": "sky is clear",
      "icon": "01n",
      "id": 800,
      "main": "Clear"
    }
  ],
  "wind": {
    "deg": 274.501,
    "speed": 4.54
  }
}

Step: Create a new Android module

  • File > New Module...
  • Android Application
  • Application Name: Weather Station
  • Module Name: appWeatherStationJson
  • Package Name: com.yourname.android.app.json.weather
  • Min SDK: 8
  • Target SDK: 19 (KitKat 4.4)
  • Compile with: 21
  • Java Lang: 6.0
  • Theme: Holo Light
  • Create Activity
  • Suport mode: Fragments
  • Suport mode: Action Bar


Next
  • Blank Activity
Next
  • MainActivity
  • activity_main
Finish


Step: add INTERNET permission

We need to add INTERNET permission since we will be accessing JSON over HTTP

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.chicagoandroid.android.app.json.weather">
    <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme">
        <activity
                android:name=".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>
    <uses-permission android:name="android.permission.INTERNET"/>
</manifest>



Android: Camera

In this tutorial we will learn how to capture an image using Android Camera and how to pass this image from a Fragment back to Activity

Step: create a new Module "appSimpleCamera"

Step: design layout in "fragment_camera.xml"






























Step: Add ImageView and Fragment container to activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              tools:context=".MainActivity"
              tools:ignore="MergeRootFrame">
    <ImageView
            android:id="@+id/picturePreviewThumb"
            android:src="@android:drawable/ic_menu_gallery"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:contentDescription="Photo Capture"
            />
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 android:id="@+id/camera_fragment_container"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"/>
</LinearLayout>



Step: implement Fragment

package com.chicagoandroid.cit299.simplecamera;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
/**
 * Camera fragment containing a simple view.
 */
public class CameraFragment extends Fragment {
   ImageView takePhoto, picturePreview, savePhoto, cancel;
   /** picturePreviewThumb belongs to Activity, not this Fragment **/
   ImageView picturePreviewThumb;
   Bitmap capturedPhoto;
   @Override
   public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      View rootView = inflater.inflate(R.layout.fragment_camera, container, false);
      return rootView;
   }
   /**
    * Add your UI elements and their functionality here,
    * because in onCreateView(...) UI does not exist yet.
    * @param savedInstanceState
    */
   @Override
   public void onActivityCreated(@Nullable Bundle savedInstanceState) {
      super.onActivityCreated(savedInstanceState);
      // Inside fragment you have to use getView()..
      cancel = (ImageView) getView().findViewById(R.id.cancel);
      takePhoto = (ImageView) getView().findViewById(R.id.takePhoto);
      savePhoto = (ImageView) getView().findViewById(R.id.savePhoto);
      savePhoto.setVisibility(View.INVISIBLE);
      picturePreview = (ImageView) getView().findViewById(R.id.picturePreview);
      takePhoto.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
            useCameraApp();
         }
      });
      savePhoto.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
            passPhotoToActivity();
         }
      });
      cancel.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
            clearScreen();
         }
      });
   }
   public void useCameraApp() {
      Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
      startActivityForResult(intent, 0);
   }
   @Override
   public void onActivityResult(int requestCode, int resultCode, Intent data) {
      super.onActivityResult(requestCode, resultCode, data);
      Bundle bundle = data.getExtras();
      /** If user presses BACK BUTTON in Camera the bundle wil be null. **/
      if (bundle != null) {
         capturedPhoto = (Bitmap) bundle.get("data");
         picturePreview.setImageBitmap(capturedPhoto);
         savePhoto.setVisibility(View.VISIBLE);
      }
   }
   private void passPhotoToActivity() {
      picturePreviewThumb = (ImageView) getActivity().findViewById(R.id.picturePreviewThumb);
      picturePreviewThumb.setImageBitmap(capturedPhoto);
   }
   private void clearScreen() {
      /** Same as android:src="@android:drawable/ic_menu_gallery" **/
      picturePreview.setImageResource(android.R.drawable.ic_menu_gallery);
      savePhoto.setVisibility(View.INVISIBLE);
   }
}



Step: implement MainActivity


package com.chicagoandroid.cit299.simplecamera;
import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends ActionBarActivity {
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      addCameraFragment(savedInstanceState);
   }
   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.main, menu);
      return true;
   }
   @Override
   public boolean onOptionsItemSelected(MenuItem item) {
      // Handle action bar item clicks here. The action bar will
      // automatically handle clicks on the Home/Up button, so long
      // as you specify a parent activity in AndroidManifest.xml.
      int id = item.getItemId();
      if (id == R.id.action_settings) {
         return true;
      }
      return super.onOptionsItemSelected(item);
   }
   /**
    * This method will be called in onCreate()
    * @param bundle savedInstanceState
    */
   private void addCameraFragment(Bundle bundle) {
      int containerId = R.id.camera_fragment_container;
      /**
       * Verify that your activity layout include a fragment container.
       * Depending on layout (size, orientation) and logic the container may not be present.
       */
      if (findViewById(containerId) == null) {
         return;
      }
      /** If restoring Activity do nothing to prevent creating existing Fragment. **/
      if (bundle != null) {
         return;
      }
      CameraFragment fragment = new CameraFragment();
      /** Pass in calling Intent's values, setting the Bundle in constructor is not recommended  **/
      // Bundle bundle = getIntent().getExtras(); //another way to get the bundle
      fragment.setArguments(bundle);
      getSupportFragmentManager().beginTransaction().add(containerId, fragment).commit();
   }
}






Android: MediaPlayer

In this tutorial we will learn how to play MP3 file saved in the application. We will create an app that plays a soothing sound of the forest (or waves, or rain) that plays in the loop. We will also learn how to control the playback.


Step 1: Create a new Module "appNatureSounds"

  • min API 8
Step 2: Design UI of your player




<RelativeLayout 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"
                tools:context=".MainActivity">
    <TextView
            android:id="@+id/uiSoundTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:text="Song Title"/>
    <LinearLayout
            android:id="@+id/controlLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_alignParentBottom="true">
        <ImageButton
                android:id="@+id/uiFastForward"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="20"
                android:layout_marginBottom="14dp"
                android:onClick="forward"
                android:src="@android:drawable/ic_media_ff"/>
        <ImageButton
                android:layout_weight="40"
                android:id="@+id/uiPlayButton"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="24dp"
                android:onClick="play"
                android:src="@android:drawable/ic_media_play"/>
        <ImageButton
                android:layout_weight="20"
                android:id="@+id/uiPausePlay"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="14dp"
                android:onClick="pause"
                android:src="@android:drawable/ic_media_pause"/>
        <ImageButton
                android:layout_weight="20"
                android:id="@+id/uiRewind"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_marginLeft="22dp"
                android:onClick="rewind"
                android:src="@android:drawable/ic_media_rew"/>
    </LinearLayout>
    <LinearLayout
            android:id="@+id/progressLayout"
            android:layout_above="@id/controlLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
        <TextView
                android:id="@+id/uiCurrentTime"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="15"
                android:text="@string/zero_time"
                android:textAppearance="?android:attr/textAppearanceSmall"/>
        <SeekBar
                android:id="@+id/uiProgressSeekBar"
                android:layout_weight="70"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        <TextView
                android:id="@+id/uiDuration"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="right"
                android:layout_gravity="right"
                android:layout_weight="15"
                android:text="@string/zero_time"
                android:textAppearance="?android:attr/textAppearanceSmall"/>
    </LinearLayout>
    <ImageView
            android:id="@+id/uiPlayerBackground"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_above="@id/progressLayout"
            android:layout_below="@+id/uiSoundTitle"
            android:src="@drawable/bg_rainforest"/>
</RelativeLayout>



Step:  Add any language specific text




<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Nature Sounds</string>
    <string name="action_settings">Settings</string>
    <string name="zero_time">0:0</string>
</resources>


Step: Record, or find a SHORT royalty-free MP3 you want to play





Step: create a class that will hold the TIME of the song.



package com.chicagoandroid.cit299.naturesounds.appnaturesounds;
import java.text.SimpleDateFormat;
/**
 * Wrapper for time mm:ss
 * Created by uki on 11/8/14.
 */
public class PlayTime {
   long time;
   public PlayTime(long value) {
      time = value;
   }
   public void update(int value) {
      time = (long) value;
   }
   public void add(int value) {
      time = time + value;
   }
   public boolean subtract(int value) {
      if (time - value > 0) {
         time = time - value;
         return true;
      }
      return false;
   }
   public PlayTime(int value) {
      time = (long) value;
   }
   public int toInt() {
      return (int) time;
   }
   public String toString() {
      SimpleDateFormat ft = new SimpleDateFormat("mm:ss");
      return ft.format(time);
   }
}





Step: MainActivity.OnCreate()



package com.chicagoandroid.cit299.naturesounds.appnaturesounds;
import android.media.MediaPlayer;
import android.os.Handler;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.Menu;
import android.view.View;
import android.widget.*;
/** Nature Sounds app */
public class MainActivity extends ActionBarActivity {
   private static int FORWARD_TIME = 5000;
   private static int REWIND_TIME = 5000;
   private static int DELAY_TIME = 100; // update 10 times per second
   private TextView soundTitle, currentTimeLabel, durationTimeLabel;
   private ImageView backgroundImage;
   private MediaPlayer mediaPlayer;
   private PlayTime currentTime = new PlayTime(0);
   private PlayTime durationTime = new PlayTime(0);
   private Handler threadHandler = new Handler();;
   private SeekBar progressSeekBar;
   private ImageButton playButton, pauseButton;
   private boolean userChangingProgress = false;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      soundTitle = (TextView) findViewById(R.id.uiSoundTitle);
      currentTimeLabel = (TextView) findViewById(R.id.uiCurrentTime);
      durationTimeLabel = (TextView) findViewById(R.id.uiDuration);
      progressSeekBar = (SeekBar) findViewById(R.id.uiProgressSeekBar);
      playButton = (ImageButton) findViewById(R.id.uiPlayButton);
      pauseButton = (ImageButton) findViewById(R.id.uiPausePlay);
      backgroundImage = (ImageView) findViewById(R.id.uiPlayerBackground);
      // set UI values to initial state before play
      durationTimeLabel.setText(durationTime.toString());
      currentTimeLabel.setText(currentTime.toString());
      progressSeekBar.setClickable(false);
      pauseButton.setEnabled(false);
      // this could be loaded from the database
      soundTitle.setText("Rain forest");
      mediaPlayer = MediaPlayer.create(this, R.raw.sound_001);
      backgroundImage.setImageResource(R.drawable.bg_rainforest);
   }


Step: play method


   public void play(View view) {
      //play sound over and over
      mediaPlayer.setLooping(true);
      mediaPlayer.start();
      toast("Playing sound");
      durationTime.update(mediaPlayer.getDuration());
      currentTime.update(mediaPlayer.getCurrentPosition());
      durationTimeLabel.setText(durationTime.toString());
      currentTimeLabel.setText(currentTime.toString());
      progressSeekBar.setProgress(currentTime.toInt());
      progressSeekBar.setMax(durationTime.toInt());
      pauseButton.setEnabled(true);
      playButton.setEnabled(false);
      threadHandler.postDelayed(SongUpdateThread, DELAY_TIME);
      progressSeekBar.setOnSeekBarChangeListener(new SeekBarListener());
   }




Step: create  SeekBarListener





   class SeekBarListener implements OnSeekBarChangeListener {
      /**
       * Notification that the progress level has changed. Clients can use the fromUser parameter
       * to distinguish user-initiated changes from those that occurred programmatically.
       *
       * @param seekBar The SeekBar whose progress has changed
       * @param progress The current progress level. This will be in the range 0..max where max
       * was set by {@link android.widget.ProgressBar#setMax(int)}. (The default value for max is 100.)
       * @param fromUser True if the progress change was initiated by the user.
       */
      @Override
      public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
         if (fromUser) {
            currentTime.update(progress);
            mediaPlayer.seekTo(currentTime.toInt());
         }
      }
      /**
       * Notification that the user has started a touch gesture. Clients may want to use this
       * to disable advancing the seekbar.
       *
       * @param seekBar The SeekBar in which the touch gesture began
       */
      @Override
      public void onStartTrackingTouch(SeekBar seekBar) {
         userChangingProgress = true;
      }
      /**
       * Notification that the user has finished a touch gesture. Clients may want to use this
       * to re-enable advancing the seekbar.
       *
       * @param seekBar The SeekBar in which the touch gesture began
       */
      @Override
      public void onStopTrackingTouch(SeekBar seekBar) {
         userChangingProgress = false;
      }
   }


Step: additional control methods




   public void pause(View view) {
      toast("Pausing sound");
      mediaPlayer.pause();
      pauseButton.setEnabled(false);
      playButton.setEnabled(true);
   }
   public void forward(View view) {
      int temp = currentTime.toInt();
      if ((temp + FORWARD_TIME) <= durationTime.toInt()) {
         currentTime.add(FORWARD_TIME);
         mediaPlayer.seekTo(currentTime.toInt());
      }
      else {
         toast("Cannot jump forward " + FORWARD_TIME / 1000 + " seconds");
      }
   }
   public void rewind(View view) {
      if ((currentTime.toInt() - REWIND_TIME) > 0) {
         currentTime.subtract(REWIND_TIME);
         mediaPlayer.seekTo(currentTime.toInt());
      }
      else {
         toast("Cannot jump backward " + REWIND_TIME / 1000 + " seconds");
      }
   }



Step: utility methods


 void toast(String text) {
      Toast toast = Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG);
      toast.setGravity(Gravity.CENTER | Gravity.CENTER, 0, 0);
      toast.show();
   }
   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      getMenuInflater().inflate(R.menu.main, menu);
      return true;
   }


Step: Song Update Thread


   private Runnable SongUpdateThread = new Runnable() {
      public void run() {
         if (!userChangingProgress) {
            currentTime.update(mediaPlayer.getCurrentPosition());
            progressSeekBar.setProgress(currentTime.toInt());
         }
         currentTimeLabel.setText(currentTime.toString());
         // call itself
         threadHandler.postDelayed(this, DELAY_TIME);
      }
   };



res/dimens.xml


   
    16dp
    16dp


Android: ADB install apk

In this tutorial you will learn frequently used Terminal commands (from your computer) to manage APKs on your Android device.


Search what APKs you have installed on your device

$ adb shell 'pm list packages -f' | grep /data/app/com.chicago
package:/data/app/com.chicagoandroid.cit299.week7.bookshelf-1.apk...
package:/data/app/com.chicagoandroid.cit299.naturesounds.appnaturesounds-1.apk...
package:/data/app/com.chicagoandroid.cit299.simplecamera-2.apk...

Uninstall APK by the package you found above.

$ adb uninstall com.your_package
$ adb uninstall com.chicagoandroid.cit299.week7.bookshelf

Success

Install APK 

in this example I am using created my Maven (mvn install), but you can use APK in the auto-generated build folder e.g.:

CIT299/appNatureSounds/build/outputs/apk/appNatureSounds-debug-unaligned.apk

$ adb install -r ~/.m2/repository/com/xyz.app_name/1.0-SNAPSHOT/app_name-x.y-SNAPSHOT.apk



Start the APK (you need to know the Activity name)


$ adb shell 'am start -n "com.your_package/com.your_packag.activity.YourMainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER'






Cron Job to keep server time up to date

This tutorial shows you how to set up a CRON (repetitive) JOB on Ubuntu Linux server to update the correct time.



NTP is a TCP/IP protocol for synchronizing time over a network. Basically a client requests the current time from a server, and uses it to set its own clock. This may lead to inconsistent logs if the clock is very inaccurate within 24 hours (should not be so), in that case investigate ntpd which is an improvement.


$ ls -l /etc/cron.daily/ntpdate
-rwxr-xr-x 1 root root 23 2014-11-04 14:02 /etc/cron.daily/ntpdate
$ cat /etc/cron.daily/ntpdate
ntpdate ntp.ubuntu.com
$ sudo chmod 755 /etc/cron.daily/ntpdate




It takes time and effort to create tutorials, please support my efforts with a couple-dollar donation, any amount will be greatly appreciated and highly motivating!



IntelliJ IDEA: code snippet auto-complete

In this tutorial I will show how to create auto-complete snippets using IntelliJ IDEA. This is a very convenient for such things as copyright information that I need to include in clients' files.



Step: Create snippet

Open Preferences > "Live Templates" > Click "+" > Create "Java > copyright" as shown in the screenshot
Abbreviation will be the keyword you will use to trigger the completion.



Step: Set what it is applicable to

Mark it for Java and XML (or any other files you may want to)


Step: Use the abbreviation



In your code start typing "copyright" and the auto-completion will suggest the right snippet.



/*
 * Copyright (C) 2014 CNH Industrial NV. All rights reserved.
 *
 * This software contains proprietary information of CNH Industrial NV. Neither
 * receipt nor possession thereof confers any right to reproduce, use, or
 * disclose in whole or in part any such information without written
 * authorization from CNH Industrial NV.
 *
 */
package com.cnh....


I hope this will save you some time!

It take time and effort to create tutorials, please support my efforts with a couple dollar donation, any amount will be greatly appreciated!



Elections 2014

Please Vote on Tuesday, November 4, 2014 in Illinois Elections.
If you feel your government does not represent your values, that is your chance.

Find out your candidates and a PLACE TO VOTE:
Research your CANDIDATES:

Sharon Hansen for Congress:
http://www.sharonhansenforussenate.org/issues

Bruce Rauner (Republican)
http://brucerauner.com/about/

Current Governor Pat Quinn (Democrat)

PLEASE SHARE!

I want people to vote..

My personal values are formed based on strong ethics the emphasize continuous learning and honest work, on my military USMC service to this country and on the fact that I was born and raised in socialist country which system I hate with passion, also on the fact that my family lived under Nazi occupation, concentration camp, etc., and that armed militia was keeping the enemy away from the forested mountains. In one of my family houses (my aunt) in mountains they did not have a German showing for 5 years of occupation because armed militia.

Personally, I want my government to share my work ethics, not my wealth. Long live the Republic.

My Political outlook?
- FEDERAL (Congress) should be Libertarian (as founding fathers intended)
- STATE should be Republican (as per constitution Art. 4, Sec. 4)
- LOCAL laws should be Democratic (you cannot get along with majority of your neighbors, move out!)
Politicians and voters should remember the above, there is no ONE fits ALL!
About issues:
  • You want to increase the minimum wage in Illinois to be higher then in other states? I worked at minimum wage, too, cleaning offices, selling in a hardware store. Just know that people in other countries WILL BE WILLING TO WORK for $7 per hour. THINK what will happen to manufacturing jobs, what will happen to prices of food and services that POOR people rely on.
  • I strongly believe that that EVERYONE should have a chance for FREE university with high academic (not sports) standards. If you are good you get free degree and contribute MORE Tax money back to society, if you don't make grades you are out. Alternatively, we can import smart people from other countries and export manufacturing jobs, where does it leave Americans? Jobless, or in school debt that is $100,000 to $240,000 depending on the school and degree.



A short lesson from Constitutional History:
The Constitution guarantees to every state a Republican form of government (Art. 4, Sec. 4). No state may join the United States unless it is a Republic. Our Republic is one dedicated to "liberty and justice for all." The first ten amendments to the Constitution, called the United States Bill of Rights, guaranteed certain natural rights fundamental to republican ideals that justified the American Revolution.The people have natural rights instead of civil rights. The people are protected by the Bill of Rights from the majority. One vote in a jury can stop all of the majority from depriving any one of the people of his rights and freedom; this would not be so if the United States were a democracy. In Democracy individuals have duties and obligations to the majority-elected government. In Republic the government has obligation to protect the rights of every individual. These ideas seem similar on the surface but that is what makes a difference between places like USA and communist and socialist states there people lost their "natural right" freedoms in name of the ideology.

Refresher on United States Bill of Rights


  • Separation of government and religion. Every person has a freedom of religion, speech, press, assembly and petition to the government of any grievances. You cannot be persecuted by government because you believe in different God, or you voice your opinion that your government is doing a bad job, or your assemble to make a peaceful demonstration (see Ferguson, Mo. 2014, where reporters were arrested for just being on the location)
  • A well regulated Militia, being necessary to the security of a free State, the right of the people to keep and bear Arms, shall not be infringed.. USA was born from an American Revolution that overthrew a legal, yet oppressive colonial government with use of Private Citizens militia. Our founding fathers wanted to ASSURE that, while the regulated military is necessary for the country, the PEOPLE should have enough military power to defend themselves from the future foes both domestic and foreign. This is not an interpretation, there are multiple document quotes from our funding fathers that explain the purpose of this essential right.
  • No Soldier shall, in time of peace be quartered in any house, without the consent of the Owner, nor in time of war, but in a manner to be prescribed by law.
"I ask sir, what is the militia? It is the whole people except for a few politicians."
- George Mason (father of the Bill of Rights and The Virginia Declaration of Rights)

"No free man shall ever be debarred the use of arms."
- Thomas Jefferson

"A free people ought to be armed."
- George Washington

"The supreme power in America cannot enforce unjust laws by the sword; because the whole body of the people are armed, and constitute a force superior to any band of regular troops."
- Noah Webster

"Americans have the right and advantage of being armed, unlike the people of other countries, whose leaders are afraid to trust them with arms."
- James Madison

"To preserve liberty, it is essential that the whole body of the people always possess arms, and be taught alike, especially when young, how to use them."
- Richard Henry Lee

"The Constitution shall never be construed to prevent the people of the United States who are peaceable citizens from keeping their own arms."
- Samuel Adams


Sources:
http://www.constitution.org/billofr_.htm
http://www.buckeyefirearms.org/gun-quotations-founding-fathers



BookShelf app: adding book cover

In this tutorial we will add a field to our model and the database.




Step 1: Add coverUrl field

public class Book {
   private int id;
   private String title;
   private String author;
   private String isbn;
   private String coverUrl;



Step 2: Create getters and setters.

Step 3: increment database version since we are modifying the structure:

 private static final int DATABASE_VERSION = 2;


Step 4: in class BookSqlHelper add field

private static final String FIELD_COVER_URL = "cover_url";
   private static final String[] COLUMNS = { //
   FIELD_ID, // 0
         FIELD_TITLE, //  1
         FIELD_AUTHOR, // 2
         FIELD_ISBN, // 3
         FIELD_LOCATION, // 4
         FIELD_COVER_URL // 5   };


Step 5: Change all CRUD methods.

for example:


   @Override
   public int update(Book book) {
      SQLiteDatabase db = this.getWritableDatabase();
      ContentValues values = new ContentValues();
      values.put(FIELD_TITLE, book.getTitle());
      values.put(FIELD_AUTHOR, book.getAuthor());
      values.put(FIELD_ISBN, book.getIsbn());
      values.put(FIELD_LOCATION, book.getLocation());
      values.put(FIELD_COVER_URL, book.getCoverUrl());