Friday, September 15, 2017

Android Java to Get JSON Data from Server via PHP

The following Android Java codes are based on Android Studio 2.3. In order for Android to obtain information from a server such as the login password verification, the easiest way is to connect to a web server via PHP. Android then establishes a connection to the server through a URL or a link to a PHP script. The following shows the PHP portion of the codes. I named this file testJSON.php:

<?php

 error_reporting(0);
 $all = array();

 if ($_GET['pc'] == "android") { // changed $_POST to $_GET on 30/11/2020
  $all[0] = array("a"=>1,"b"=>2,"c"=>3);
  $all[1] = array("d"=>4,"e"=>5,"f"=>6);
  $all[2] = array("g"=>7,"h"=>8,"i"=>9);
 }

 $encoded = json_encode($all);
 header('Content-type: application/json');
 exit($encoded);

?>


The following will be the codes from the Android Studio side. But before going into the Java coding, one must make sure Android can access to the Internet. This can be achieved by adding the following line in red in the AndroidManifest.xml file.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.example.eric.testjson">

 <application
  android:allowBackup="true"
  android:icon="@mipmap/ic_launcher"
  android:label="@string/app_name"
  android:roundIcon="@mipmap/ic_launcher_round"
  android:supportsRtl="true"
  android:theme="@style/AppTheme">
  <activity android:name=".MainActivity">
   <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>


The following codes are from the main Android Java called MainActivity.java:

package com.example.eric.testjson; // Your package name will be different, there is no need to paste this code to your MainActivity.java file.

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  new grabFromPHPServer(this).execute("android"); // "android" is a parameter that will be passed to doInBackground in grabFromPHPServer Java sub class
 }
}


The following codes are from the Java class called grabFromPHPServer.java. You can create this Java class by right clicking your Java folder.

package com.example.eric.testjson; // you use your own package info, no need to paste this to your java file

import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;

public class grabFromPHPServer extends AsyncTask<String, Void, String> {

 private Context context;

 public grabFromPHPServer(Context context) {
  this.context = context;
 }

 protected void onPreExecute() {

 }

 @Override
 protected String doInBackground(String... arg) {

  String passcode = arg[0];
  String link;
  String data;
  BufferedReader bufferedReader;
  String result;

  Log.d("result","start trying to grab from PHP server...");
  try {
   Log.d("result","preparing parameter sent to server...");

   data = "?pc=" + URLEncoder.encode(passcode, "UTF-8");

   link = "http://www.yourOwnURL.com/testJSON.php"+data;
   URL url = new URL(link);
   HttpURLConnection con = (HttpURLConnection) url.openConnection();
   Log.d("result","connection response: "+con.toString());

   bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
   //result = bufferedReader.readLine(); // commented out and replaced with the following on 30th of November 2020
   String strLine;
   while ((strLine = bufferedReader.readLine()) != null)
   {
      if (!strLine.isEmpty()) {
         result += strLine;
      }
   }

   Log.d("result",result.toString()); // spit all JSON data received

   String jSONString = result;
   if (jSONString != null) {
    Log.d("result", "jSON received: "+jSONString.toString());
    JSONArray jsonArr = new JSONArray(jSONString);
    JSONObject query_result = jsonArr.getJSONObject(0);
    Log.d("result", "a->"+query_result.getString("a"));
    query_result = jsonArr.getJSONObject(1);
    Log.d("result", "e->"+query_result.getString("e"));
    query_result = jsonArr.getJSONObject(2);
    Log.d("result", "g->"+query_result.getString("g"));
   }
   else {
    Log.d("result", "jSON received is null");
   }
   return result;
  } catch (Exception e) {
   Log.d("result","grab failed");
   return new String("Exception: " + e.getMessage());
  }
 }

 @Override
 protected void onPostExecute(String result) {
  // you can also process your jSON here
 }
}


AsyncTask extension is crucial in the Java class as it is quite meaningless if you run the connection in your main activity Java class as the connection takes time and you will get an exception error if the JSON data failed to be received within a short period of wait time. But in order to use AsyncTask extension, you need to create a sub class to handle background tasks such as this grabFromPHPServer.java sub class. Please also replace yourOwnURL with your own domain name where your PHP file resides.

The following is the screen shot I took from my Android Monitor. The log is filtered with the keyword 'result' so that I only see output from my very own Log.d results:

Read More »

Monday, August 28, 2017

Javascript to Limit HTML Width for Mobile Devices of Any Orientation

The viewport parameter in the HTML Meta Tag is used to limit the screen width. Another thing to pay attention for these codes is the neccessity to differentiate between tablets and phones. Phones tend to have less resolution whereas tablets can have resolutions comparable to that of PC or Mac. I use a simple criteria to differentiate the two by checking the screen width whether it is wider than 700 pixels. If so, tablets' width will be forced to limit to only 700 pixels. For non-tablets, the width will be limited to the native screen width found in the Javascript system parameter screen.width. Pay attention to when orientation changes. Android will have the width and height paramters swapped whereas the mobile Safari will have the same width and height irregardless of the orientation.

The <body> onorientationchange is used to listen to the orientation change even. Whenever it is fired, the 'content' meta will be reconfigured according to the orientation status. Javascript's window.orientation is used to check the current orientation status in terms of degrees.

Let's jump into the codes:

<html>
<head>
<title>Javascript to Limit HTML Width for Mobile Devices of Any Orientation</title>

<script>

var mobile = navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/iPhone|iPad|iPod/i) || navigator.userAgent.match(/Opera Mini/i) || navigator.userAgent.match(/IEMobile/i);

var safari = navigator.userAgent.match(/iPhone|iPad|iPod/i) && navigator.userAgent.match(/Safari/i);

var ot = ""; // variable "orientation" is used by mobile browsers
if (safari) {
 if (window.orientation == 0) { ot="portrait"; } else { ot="landscape"; }
}
else {
 if (screen.width<screen.height) { ot="portrait"; } else { ot="landscape"; }
}


if (mobile) {
 var mobileWidth = getMobileWidth();
 alert("setting the width of "+mobileWidth);
 document.write('<meta id="vp" name="viewport" content="width = '+mobileWidth+', initial-scale=1.0">');
}
// if it is not mobile, viewport is not supported or will be ignored

function getMobileWidth() {
 var width;
 var isTablet = 0;
 if (safari) { // safari screen width and height remain constant irregradless of the orientation
  if (ot == "portrait") { width = screen.width; if (width>400) {isTablet=1;} }
  else { width = screen.height; if (width>700) {isTablet=1;} }
 }
 else {
  width = screen.width;
  if (ot == "portrait") { if (width>400) {isTablet=1;} }
  else { if (width>700) { isTablet=1;} }
 }
 if (isTablet) {
  if (ot == "portrait") {
   return 400;
  }
  else {
   return 700;
  }
 }
 else {
  return width;
 }
}

function changeViewPort() { //change viewport dynamically by changing the meta 'content' attribute

 if (safari) { // mobile safari will not swap screen.width with screen.height after orientation change
  if (window.orientation == 0) { ot="portrait"; } else { ot="landscape"; }
 }
 else { // other broswers will have height and width swapped
  if (screen.width<screen.height) { ot="portrait"; } else { ot="landscape"; }
 }

 var mobileWidth = getMobileWidth();
 alert("setting the width of "+mobileWidth);
 alert("screen in "+ot+" mode w:"+screen.width+" h:"+screen.height+" -->"+window.orientation);

 if (mobile) {
  var vp = document.getElementById('vp');
  vp.setAttribute('content','width='+mobileWidth+', initial-scale=1.0');
 }
}

</script>

</head>

<body bgcolor=orange onorientationchange="changeViewPort()">

<table width=100% height=100% align=center valign=middle>
<tr><td width=100% height=100% align=center valign=middle style="font-family: Lucida Sans, Lucida Sans Unicode, Helvetica, Arial, sans-serif;">Under Construction</td></tr>
</table>

</body>

</html>


Please note the meta tag has been given an ID (id="vp") so that it can be modified when necessary. onorientationchange is used instead of "onresize" as "onresize" will make give a lots of false signal even when the address bar in mobile browsers shows up or hides.

Read More »