Downloading internet content and apps about the worlds richest celebrities

In the continuing saga of my Android Developer Course with Rob Percival, I needed to make an app that would show a picture of a famous celebrity, and give the user a multiple choice quiz on who it was. Once clicked, it should tell you if you pass or fail, and load the next picture and names.

I decided to be different. Instead, I chose to have one name and four pictures. You can download the app here:

http://www.mediafire.com/file/srrey66ma3hxe5i/guesstherichcelebrity.apk

device-2017-03-13-131637

But be warned, when you click on your celebrity choice, you have to wait until it puts up a right/wrong toast before clicking again. Oh, you can click again, and it will not crash, but then you will only prolong the wait, which is a bit lengthy, due to my fledgling Java skills. Or maybe it is just my slow internet. Either way, be patient.

The way I went about doing this in my app was actually quite a bit different than that of my instructors. His way was much more streamlined and worked faster. I was happy that mine did work, though, Praise God!

Here’s what I did:

MainActivity.java

[CODE]
/* Copyright 2017 by AlaskaLinuxUser (https://thealaskalinuxuser.wordpress.com)
*
* Licensed under the Apache License, Version 2.0 (the “License”);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an “AS IS” BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alaskalinuxuser.guessthatceleb;

// Import some libraries….
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.os.AsyncTask;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MainActivity extends AppCompatActivity {

// Declare our strings, integers, imageviews, bitmaps, and textviews.
String result;
int celebNum;
int aCeleb;
int rightAnswer;
String foundString;
String whosWho;
String whosName;
String whoWins;
ImageView picOne;
ImageView picTwo;
ImageView picThree;
ImageView picFour;
TextView nameText;
Bitmap winningPic;
Bitmap myBit;

// Our new class to download the page html data to parse for info.
public class DownloadPage extends AsyncTask<String, Void, String> {

// Do this in the background.
@Override
protected String doInBackground(String… urls) {

// A few declared items.
result = “”;
URL url;
HttpURLConnection urlConnection = null;
//Log.i(“WJH”, urls[0]); // To log that the URL arrived in the class when called.

// Try this.
try {

// Make our URL based on our given url to lookup.
url = new URL(urls[0]);

// Make a connection for that URL and open it.
urlConnection = (HttpURLConnection) url.openConnection();

// Start an input stream to get the bits.
InputStream in = urlConnection.getInputStream();

// Buffer it to reader.
BufferedReader reader = new BufferedReader(new InputStreamReader(in, “iso-8859-1”), 8);

// Build it string by string.
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) // Read line by line
sb.append(line + “\n”);

// Here is the result.
String resString = sb.toString();

// Close the stream.
in.close();

// Tie the result to our variable that is known outside of this class.
result = resString;

// return that variable.
return result;

// Have an exception clause so you don’t crash.
} catch (Exception e) {

e.printStackTrace();

return “Failed”;

}

}

}

// Our new class to download the picture in the background.
public class DownloadPic extends AsyncTask<String, Void, Bitmap> {

@Override
protected Bitmap doInBackground(String… urls) {

String result = “”;
URL url;
HttpURLConnection urlConnection;

try {

url = new URL(urls[0]);

urlConnection = (HttpURLConnection) url.openConnection();

// To download in one “go” as Rob says.
urlConnection.connect();

// To grab the whole thing at once.
InputStream inStream = urlConnection.getInputStream();

// Turn that data into a bitmap.
myBit = BitmapFactory.decodeStream(inStream);

// Return that bitmap.
return myBit;

// Have an exception if there is a failure.
} catch (Exception e) {

e.printStackTrace();

//Log.i(“WJH”, “Failed”); // You can log this to see the failure if needed.

// Since it fails, return nothing.
return null;

}

}
}

// Our random number generator.
public void randomIzer() {

// The random number generator itself.
Random ranGen = new Random();

// The random number of richest celebrities.
celebNum = ranGen.nextInt(20);

// The random number of the right answer.
rightAnswer = ranGen.nextInt(4);

//Log.i(“WJH”, Integer.toString(rightAnswer)); // Log this to test the random number answer.

}

// Our method to get the name of the celebrity.
public void getCelebname(){

// Call the class to download the page.
DownloadPage task = new DownloadPage();
String result = null;

// my trick number we will use later.
aCeleb=0;

try {

// execute, or go on and do that task.
result = task.execute(“http://www.therichest.com/top-lists/top-100-richest-celebrities&#8221;).get();

// A fail clause.
} catch (Exception e) {

e.printStackTrace();

}

// Now regex the data with this pattern.
Pattern pat = Pattern.compile(“<span>(.*?)</span>”);

// And search for matches in the results.
Matcher mat = pat.matcher(result);

// For every one you find, do this.
while (mat.find() && aCeleb <= celebNum) {

// Add to my magic number.
aCeleb++;

// The search results.
String foundNameString = (mat.group(1));

// Tie the search results to a public variable we can use outside of this method.
whosName = foundNameString;

//Log.i(“WJH”, whosName); // Log to see if this is working.

}

}

// And a method to figure out which picture we need. Same as above method, just a different
// search pattern.
public void getCelebpic(){

DownloadPage task = new DownloadPage();
String result = null;
aCeleb=0;

try {

result = task.execute(“http://www.therichest.com/top-lists/top-100-richest-celebrities&#8221;).get();

} catch (Exception e) {

e.printStackTrace();

}

Pattern pat = Pattern.compile(“0px\\)\” sizes=\”70px\” srcset=\”(.*?)\””);

Matcher mat = pat.matcher(result);

while (mat.find() && aCeleb <= celebNum – 1) {

aCeleb++;

foundString = (mat.group(1));

whosWho = foundString;

//Log.i(“WJH”, foundString); // Log to see if this is working.

}

}

// Ok, now we need to download that picture.
public void downloadPics(){

// Call the class to download the picture.
DownloadPic task = new DownloadPic();

try {

// Let’s get the picture.
Bitmap myImage = task.execute(whosWho).get();

} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}

}

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

// Define a few objects.
picOne = (ImageView)findViewById(R.id.imageViewZero);
picTwo = (ImageView)findViewById(R.id.imageViewOne);
picThree = (ImageView)findViewById(R.id.imageViewTwo);
picFour = (ImageView)findViewById(R.id.imageViewThree);
nameText = (TextView)findViewById(R.id.nameView);

// Set up our first round.
setupGame();

}

// The method to set up each round of choices.
public void setupGame() {

// Call the randomizer method.
randomIzer();

// Okay, so the real winner is:
// Get the winner name.
getCelebname();
// Set the winner name to the text field.
nameText.setText(whosName);
// Get the URL for the celeb pic.
getCelebpic();
// Tie in our winning variable, since we will overwrite it later.
whoWins = whosWho;
// Call the method to download the pic.
downloadPics();
// Tie in our winning pic to our downloaded pic, since we will overwrite it later.
winningPic = myBit;

// if/then. if you are the right answer, set your pic to the winning pic.
if (rightAnswer == 0) {

picOne.setImageBitmap(winningPic);

} else {

// If not, then plus one on the celebNum and call for a random picture.
celebNum++;
getCelebpic();
downloadPics();
picOne.setImageBitmap(myBit);

}

if (rightAnswer == 1) {

picTwo.setImageBitmap(winningPic);

} else {

celebNum++;
getCelebpic();
downloadPics();
picTwo.setImageBitmap(myBit);

}

if (rightAnswer == 2) {

picThree.setImageBitmap(winningPic);

} else {

celebNum++;
getCelebpic();
downloadPics();
picThree.setImageBitmap(myBit);

}

if (rightAnswer == 3) {

picFour.setImageBitmap(winningPic);

} else {

celebNum++;
getCelebpic();
downloadPics();
picFour.setImageBitmap(myBit);

}
}

// Well, am I right? This is called through onClick of each imageview.
public void amIRight(View view){

// Make a tag number string with get tag for the clicked object.
String tagNum = (String) view.getTag();
//Log.i(“WJH”, Integer.toString(rightAnswer)); // Log to see if this is working.
//Log.i(“WJH”, tagNum); // Log to see if this is working.
// Parse the integer from the string.
int taggedNum = Integer.parseInt(tagNum);
// Define a toast text for later.
String toastText;

// If the tagged number of the clicked square is the right answer….
if (taggedNum == rightAnswer) {

// Set the text to correct.
toastText = “Correct!”;

// If not….
} else {

// Set the text to incorrect.
toastText = “Incorrect.”;

}

// Set up the next round.
setupGame();

// And tell the user if they were right or not.
Toast.makeText(getApplicationContext(), toastText, Toast.LENGTH_LONG).show();

/* This may seem a bit odd. Logic would dictate we toast first, then set up the
* next round. But, if I toast first, the toast does not display because the phone
* is working too hard to get the new pictures. This way, we wait until the new pictures
* are in, then display the toast, which works, but seems sloppy.
*/
}
}
[/CODE]

And the activity_main.xml

[CODE]
<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout
xmlns:android=”http://schemas.android.com/apk/res/android&#8221;
xmlns:app=”http://schemas.android.com/apk/res-auto&#8221;
xmlns:tools=”http://schemas.android.com/tools&#8221;
android:id=”@+id/activity_main”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:orientation=”vertical”
android:paddingLeft=”@dimen/activity_horizontal_margin”
android:paddingRight=”@dimen/activity_horizontal_margin”
android:paddingTop=”@dimen/activity_vertical_margin”
android:paddingBottom=”@dimen/activity_vertical_margin”
tools:context=”com.alaskalinuxuser.guessthatceleb.MainActivity”
android:gravity=”top|center_horizontal”>

<TextView
android:text=”TextView”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_alignParentTop=”true”
android:layout_centerHorizontal=”true”
android:id=”@+id/nameView”
android:textSize=”40sp”
android:layout_margin=”25dp” />

<GridLayout
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”
android:rowCount=”2″
android:columnCount=”2″>

<ImageView
android:layout_height=”150dp”
android:layout_width=”150dp”
android:src=”@mipmap/ic_launcher”
android:layout_row=”0″
android:layout_column=”0″
android:tag=”0″
android:onClick=”amIRight”
android:id=”@+id/imageViewZero” />

<ImageView
android:layout_height=”150dp”
android:layout_width=”150dp”
android:src=”@mipmap/ic_launcher”
android:layout_row=”0″
android:layout_column=”1″
android:tag=”1″
android:onClick=”amIRight”
android:id=”@+id/imageViewOne” />

<ImageView
android:layout_height=”150dp”
android:layout_width=”150dp”
android:src=”@mipmap/ic_launcher”
android:layout_row=”1″
android:layout_column=”0″
android:tag=”2″
android:onClick=”amIRight”
android:id=”@+id/imageViewTwo” />

<ImageView
android:layout_height=”150dp”
android:layout_width=”150dp”
android:src=”@mipmap/ic_launcher”
android:layout_row=”1″
android:layout_column=”1″
android:tag=”3″
android:onClick=”amIRight”
android:id=”@+id/imageViewThree” />

</GridLayout>
</LinearLayout>
[/CODE]

Of course, don’t forget to add internet permission in the AndroidManifest.xml:

[CODE]
<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android&#8221;
package=”com.alaskalinuxuser.guessthatceleb” >

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

<application
android:allowBackup=”true”
android:icon=”@mipmap/ic_launcher”
android:label=”@string/app_name”
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>

</manifest>
[/CODE]

All of the java has notes sprinkled throughout for definitions of what I am trying to attempt. Be sure to check it out, and if you find it useful, be sure to use it! You can always check my github for these small apps if you want to download it and test out some other methods or use it in your own projects.

Linux – keep it simple.

 

A brain teaser app!

For my continued education, I was required to make a brain teaser app which had several elements. Here is a download link if you want to try the finished product:

http://www.mediafire.com/file/xgmsnxqy58gdq8f/brain_test.apk

device-2017-03-06-083331

The whole thing hinged on this random number generator. I particularly struggled with this. I needed to have a question (x + y) and then have four random answers to pick from, only having one of which as the answer. At first I was working it from the beginning to the end: coming up with random x, and then adding random y, and then putting that into the text boxes randomly and making some new numbers. But, I eventually realized that I was working the problem the “long way around”.

Instead, I decided to make just one random answer, and split that into my question instead. This became much simpler. There are probably better ways to do this, but here is what I put together:

[CODE]
// And we need a random number generator.
public void randomNumber() {

// The actual number generator.
Random smallGen = new Random();

// To pick the tile threat is the answer.
// Remember: 0 is a number.
answerNum = smallGen.nextInt(4);

// Now to pick a number between 1 and 20.
// And assign that number to each tile.
randNumZero = smallGen.nextInt(19) + 1;
p0.setText(String.valueOf(randNumZero));

randNumOne = randNumZero + 6;
p1.setText(String.valueOf(randNumOne));

randNumTwo = randNumZero – 1;
p2.setText(String.valueOf(randNumTwo));

randNumThree = randNumZero + 3;
p3.setText(String.valueOf(randNumThree));

// And our random first number of our question.
// A number between 1 and 20. We will minus this from
// the answer to get the second number.
firstNum = smallGen.nextInt(19) + 1;

// Now to get the question.
if (answerNum == 0) {

secondNum = randNumZero – firstNum;

} else if (answerNum == 1) {

secondNum = randNumOne – firstNum;

} else if (answerNum == 2) {

secondNum = randNumTwo – firstNum;

} else {

secondNum = randNumThree – firstNum;

}

String fN = String.valueOf(firstNum);
String sN = String.valueOf(secondNum);

questionView.setText(fN + ” + ” + sN);

}
[/CODE]

Which worked great. Originally, I had created four random possible answers and then chose one at random as THE answer. However, I came to realize that sometimes the random possible answers could be the same as the random answer itself. That is when I changed randNumZero to be the only truly random number, the other randomNum objects are set additives and detraction from the actual random number. That makes them random to a point, since they are based from the random number.

After these possible answers are made, I then randomly choose one of them to be the answer, and from that minus a random number to get my two numbers for the question (the small minus random number and the derivative). Praise God! It even worked! This had an added benefit of allowing negative numbers, which really challenges the user’s math skills, since you only have 30 seconds to answer as many questions as possible.

Enjoy the math game!

Linux – keep it simple

Countdown or Runnable and Handler, what’s the difference?

Today in class, we learned about different types of timers. Specifically, we learned the difference between a countdown timer, and a runnable and handler. Here’s the app that I put together based on the class:

http://www.mediafire.com/file/0xgqkkbqjaztjmw/thefinalcountdown.apk

It’s not very exciting, hense no screenshot. It has three different toast messages going on at the same time. The first is a toast every seven seconds to tell you it has been seven seconds. The second is a toast every ten seconds telling you how much time is left on the countdown timer, and the third tells you that the countdown is complete.

Here is the Handler and runnable:

[CODE]

// Up first, the Handler and runnable!

// Create the handler, give it a name.
final Handler firstHandler = new Handler();

// Now create a runnable, give it a name.
Runnable firstRun = new Runnable() {

// Now, have that runnable override and run some code.
@Override
public void run() {

// In this case, make a toast.
Toast myToast = Toast.makeText(getApplicationContext(), “It’s been 7 seconds.”, Toast.LENGTH_SHORT);
myToast.setGravity(Gravity.CENTER, 0, 0);
myToast.show();

// And call itself again in 7 seconds….
firstHandler.postDelayed(this, 7000);

}

};

// Be sure to initiate the handler the first time, or nothing will happen.
// You could just use firstHandler.post(firstRun); but I wanted to wait seven seconds first.
firstHandler.postDelayed(firstRun, 7000);
[/CODE]

And here is the countdown timer:

[CODE]

// Up next, the countdown timer! Give it a lenght and an amount to count down in milliseconds.
new CountDownTimer(121000, 10000) {

// Implement code to happen every tick of the countdown.
public void onTick (long myTimer) {

// In this case a toast.
Toast.makeText(
getApplicationContext(), “Ten seconds passed, ” + String.valueOf(myTimer / 1000) + ” seconds left!”, Toast.LENGTH_SHORT).show();

}

// Implement code to happen when it is done counting down.
public void onFinish() {

// Again, I used a toast.
Toast.makeText(getApplicationContext(), “Countdown is complete!”, Toast.LENGTH_SHORT).show();

}

// Tell the countdown timer to start!
}.start();

}
[/CODE]

So, what’s the difference? Well, from what Rob was saying, the key difference is that the Countdown timer and Handler/Runnable can do the exact same thing. However, the Countdown timer has a way of destroying itself when it is done.

At first I thought, “oh, the countdown timer will stop eventually, and the handler/runnable will not”. However, that is an error, because we could make the handler/runnable only display x number of times, by using a variable and minus 1 from it every time.
Like this:

[CODE]
…..

public int a = 10;

…..

// Create the handler, give it a name.
final Handler firstHandler = new Handler();

// Now create a runnable, give it a name.
Runnable firstRun = new Runnable() {

// Now, have that runnable override and run some code.
@Override
public void run() {

// In this case, make a toast.
Toast myToast = Toast.makeText(getApplicationContext(), “It’s been 7 seconds.”, Toast.LENGTH_SHORT);
myToast.setGravity(Gravity.CENTER, 0, 0);
myToast.show();

a = a-1;

if (a >= 0) {

// And call itself again in 7 seconds….
firstHandler.postDelayed(this, 7000);

} else {
// do nothing, or a toast that says “I’m done.”
}

}

};

// Be sure to initiate the handler the first time, or nothing will happen.
// You could just use firstHandler.post(firstRun); but I wanted to wait seven seconds first.
firstHandler.postDelayed(firstRun, 7000);
[/CODE]

Once it reaches 0, it could use an if/then statement to not call itself to run again. So, the two can litterally function the same, it is just a matter of being “left over” after you are done with it. Interesting.

So, the pros to using a handler/runnable is that you can call it from other functions, and it can run on indefinately.
And, a pro for using the countdown timer is that you can easily get the remaining time for display or use as a variable.

Perhaps I will learn new differences that may make one more prominent than the other. Only time will tell. Okay, bad pun, bad pun….

Linux – keep it simple.

 

Testing out List Views in Android app development

Today, in my Android App Developer Course by Rob Percival, he showed us how to make lists in our apps. As is his style, he shows us the meat and potatoes of something, and then challenges us to garnish it.

During the challenge, we were supposed to make the list clickable, and when clicked, have it pop-up with a toast to say what item in the list you clicked on. This is mostly just a note for my own reference, but after completing the challenge, Rob showed us a much cleaner way to do that. His method reduced 2 of my lines down to one. Here’s what I did:

MainActivity.java

[CODE]

package com.alaskalinuxuser.testlistviews;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.view.View;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;
import java.lang.String;


public class MainActivity extends AppCompatActivity {

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

        // Defining the list view that I want by id.
        final ListView theList = (ListView) findViewById(R.id.theList);

        // Defining an array of names.
        final List myList = new ArrayList();

        // Adding names to the array list.
        myList.add("Dad");
        myList.add("Mom");
        myList.add("Brother");
        myList.add("Sister");
        myList.add("Uncle");
        myList.add("Aunt");
        myList.add("Grandma");
        myList.add("Grandpa");
        myList.add("First Cousin");
        myList.add("Second Cousin");
        myList.add("Double Cousin");
        myList.add("Friend");

        // Defining an adapter, to adapt my array list to the correct format.
        ArrayAdapter<String> addaptedAray = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myList);

        // Using the adapter to adapt my array list to the defined list view that I declared already.
        theList.setAdapter(addaptedAray);

        // Setting up a listener to "listen" for me to click on something in the list.
        theList.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            // Overriding the generic code that Android uses for list views to do something specific.
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int z, long l) {

                /*
                 * My method, that I came up with during the class....
                 */
                // Converting the integer of "z" to a string with the name of the item clicked in the list.
                String a = (String) myList.get(z);

                // Logging that I tapped said item in the list.
                Log.i("tapped", a);

                // A simple toast to inform the user of what they clicked on in the list.
                Toast.makeText(getApplicationContext(), "Hi " + a , Toast.LENGTH_LONG).show();

                /*
                 * The method that Rob showed us in the class.... Much simpler code, very straight forward.
                 * public void onItemClick(AdapterView<?> adapterView, View view, int z, long l) {
                 *
                 * Toast.makeText(getApplicationContext(), "Hello " + myList.get(z) , Toast.LENGTH_LONG).show();
                 *
                 * }
                 */

            }
        });


    }
}

[/CODE]

activity_main.xml

[CODE]

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    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="com.alaskalinuxuser.testlistviews.MainActivity">

    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:id="@+id/theList" />
</RelativeLayout>

[/CODE]

Herein lies the key part, though, where I differed from the instructor….

my way:

[CODE]

public void onItemClick(AdapterView<?> adapterView, View view, int z, long l) {

    /*
     * My method, that I came up with during the class....
     */
    // Converting the integer of "z" to a string with the name of the item clicked in the list.
    String a = (String) myList.get(z);

    // Logging that I tapped said item in the list.
    Log.i("tapped", a);

    // A simple toast to inform the user of what they clicked on in the list.
    Toast.makeText(getApplicationContext(), "Hi " + a , Toast.LENGTH_LONG).show();

[/CODE]

The better, cleaner way, as shown by Rob:

[CODE]

public void onItemClick(AdapterView adapterView, View view, int z, long l) {

 Toast.makeText(getApplicationContext(), "Hello " + myList.get(z) , Toast.LENGTH_LONG).show();

 }

Android: making a soundboard app!

I call it “Finnish On The Go”, essentially a soundboard app that plays a sound every time you click a button. The buttons are programmed to play the sound corresponding to the spoken Finnish words of the phrase you click on. As part of my course for Android development, the goal was to make an app that might help you if you were traveling to a foreign country, in this case Finland. Here is the app I made if you want to test it out:

http://www.mediafire.com/file/bwbqqtgki0bwlmq/FinishOnTheGo.apk

And here are the files:

AndroidManifest.xml

[CODE]
<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android&#8221;
package=”com.alaskalinuxuser.finnishonthego”>

<application
android:allowBackup=”true”
android:icon=”@drawable/icon_finland”
android:label=”@string/app_name”
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>

</manifest>
[/CODE]

MainActivity.java

[CODE]
/* Copyright 2017 AlaskaLinuxUser
*
*Licensed under the Apache License, Version 2.0 (the “License”);
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an “AS IS” BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License. */

package com.alaskalinuxuser.finnishonthego;

import android.content.Context;
import android.media.MediaPlayer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

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

}

public void playClip0 (View view) {
playSoundClip(R.raw.hello_fi);
}

public void playClip1 (View view) {
playSoundClip(R.raw.goodbye_fin);
}

public void playClip2 (View view) {
playSoundClip(R.raw.howtosay_fin);
}

public void playClip3 (View view) {
playSoundClip(R.raw.nounderstand_fin);
}

public void playClip4 (View view) {
playSoundClip(R.raw.thanks2_fin);
}

public void playClip5 (View view) {
playSoundClip(R.raw.sorry_fin);
}

public void playClip6 (View view) {
playSoundClip(R.raw.mynameis_fin);
}

public void playClip7 (View view) {
playSoundClip(R.raw.whatyourname_fin);
}

public void playSoundClip(int handle){

Context appContext = getApplicationContext();
MediaPlayer mp = MediaPlayer.create(appContext , handle);
mp.start();

}

}
[/CODE]

activity_main.xml

[CODE]
<?xml version=”1.0″ encoding=”utf-8″?>
<RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android&#8221;
xmlns:tools=”http://schemas.android.com/tools&#8221;
android:id=”@+id/activity_main”
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=”com.alaskalinuxuser.finnishonthego.MainActivity”>

<GridLayout
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”
android:columnCount=”2″
android:rowCount=”4″>

<Button
android:text=”Hello”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_column=”0″
android:layout_row=”0″
android:layout_rowWeight=”1″
android:layout_columnWeight=”1″
android:layout_gravity=”fill”
android:tag=”0″
android:onClick=”playClip0″
android:id=”@+id/button” />

<Button
android:text=”Goodbye”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_column=”1″
android:layout_row=”0″
android:layout_rowWeight=”1″
android:layout_columnWeight=”1″
android:layout_gravity=”fill”
android:tag=”1″
android:onClick=”playClip1″
android:id=”@+id/button1″ />

<Button
android:text=”How do I say …”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_column=”0″
android:layout_row=”1″
android:layout_rowWeight=”1″
android:layout_columnWeight=”1″
android:layout_gravity=”fill”
android:tag=”2″
android:onClick=”playClip2″
android:id=”@+id/button2″ />

<Button
android:text=”I don’t understand.”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_column=”1″
android:layout_row=”1″
android:layout_rowWeight=”1″
android:layout_columnWeight=”1″
android:layout_gravity=”fill”
android:tag=”3″
android:onClick=”playClip3″
android:id=”@+id/button3″ />

<Button
android:text=”Thanks!”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_column=”0″
android:layout_row=”2″
android:layout_rowWeight=”1″
android:layout_columnWeight=”1″
android:layout_gravity=”fill”
android:tag=”4″
android:onClick=”playClip4″
android:id=”@+id/button4″ />

<Button
android:text=”I’m sorry.”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_column=”1″
android:layout_row=”2″
android:layout_rowWeight=”1″
android:layout_columnWeight=”1″
android:layout_gravity=”fill”
android:tag=”5″
android:onClick=”playClip5″
android:id=”@+id/button5″ />

<Button
android:text=”My name is …”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_column=”0″
android:layout_row=”3″
android:layout_rowWeight=”1″
android:layout_columnWeight=”1″
android:layout_gravity=”fill”
android:tag=”6″
android:onClick=”playClip6″
android:id=”@+id/button6″ />

<Button
android:text=”What is your name?”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_column=”1″
android:layout_row=”3″
android:layout_rowWeight=”1″
android:layout_columnWeight=”1″
android:layout_gravity=”fill”
android:tag=”7″
android:onClick=”playClip7″
android:id=”@+id/button7″ />

</GridLayout>
</RelativeLayout>
[/CODE]

So that is how I did it. However, after completing the project, the instructor showed us a much better way to do that, with slight modification, as we see here:

First, I had to change the activity_main.xml, and edit the onclick function to be the same for every button. I also needed to change the id to be the same name as the name of the audio file in the “raw” folder. Here’s an exerpt:

[CODE]
<Button
android:text=”I don’t understand.”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_column=”1″
android:layout_row=”1″
android:layout_rowWeight=”1″
android:layout_columnWeight=”1″
android:layout_gravity=”fill”
android:tag=”3″
android:onClick=”playClip”
android:id=”@+id/understand” />

<Button
android:text=”Thanks!”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_column=”0″
android:layout_row=”2″
android:layout_rowWeight=”1″
android:layout_columnWeight=”1″
android:layout_gravity=”fill”
android:tag=”4″
android:onClick=”playClip”
android:id=”@+id/thanks” />
[/CODE]

Then, I completely redid the MainActivity.java in accordance with what the course taught:

[CODE]
/* Copyright 2017 AlaskaLinuxUser
*
*Licensed under the Apache License, Version 2.0 (the “License”);
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an “AS IS” BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License. */

package com.alaskalinuxuser.finnishonthego;

import android.content.Context;
import android.media.MediaPlayer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

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

}

public void playClip (View myView) {

int theId = myView.getId();
String theButton = “”;

theButton = myView.getResources().getResourceEntryName(theId);

int resId = getResources().getIdentifier(theButton, “raw”, “com.alaskalinuxuser.finnishonthego”);

MediaPlayer mp = MediaPlayer.create(this, resId);
mp.start();
}

}
[/CODE]

Once I ran that, it worked identical to what I had made, however, as you can see, Rob’s version has way more expandability, as well as a cleaner code. Pretty neat! Here is the download for 2.0, if you want to compare the apps:

http://www.mediafire.com/file/z8eq18zw2xwxnwm/FinnishOnTheGo_2_0.apk

Linux – keep it simple.

 

Cross-fade and other animations!

So I enlisted the help of Borris and Natasha to chase down Rocky and Bullwinkle in my supped up app from the last post: Crossfade.

Here is the latest version:

http://www.mediafire.com/file/c966u578x0h1x7a/crossfade_1_1.apk

If you downloaded this app last time, you saw two different methods to transition, or fade out one image, and fade in a different one. Today, we are taking this to a whole new level! Not only do you have an image transition, but you also have a spinning image, an image that grows, and two images that move off and onto the screen. Check out my comments in the code if you want to see what I did.

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    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="com.alaskalinuxuser.crossfade.MainActivity">

    <ImageView
        android:layout_width="200sp"
        android:layout_height="200sp"
        app:srcCompat="@drawable/transition"
        android:id="@+id/imageView"
        android:onClick="crossFade"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <ImageView
        android:layout_width="200sp"
        android:layout_height="200sp"
        app:srcCompat="@drawable/rocky"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:onClick="spinner"
        android:id="@+id/imageView2" />

    <ImageView
        android:layout_width="200sp"
        android:layout_height="200sp"
        app:srcCompat="@drawable/bull"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:id="@+id/imageView3"
        android:onClick="doubleTrouble" />

    <ImageView
        android:layout_width="45sp"
        android:layout_height="45sp"
        app:srcCompat="@drawable/badguys"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:onClick="sizeMe"
        android:id="@+id/imageView4" />
</RelativeLayout>

MainActivity.java

package com.alaskalinuxuser.crossfade;

import android.graphics.drawable.TransitionDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.*;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {

    public void crossFade (View view){

        /* First things first, transition between all of the
        * images in the tansition.xml file. In this case, there
        * are only two.
        */
        // Define the image view that is used
        ImageView picture = (ImageView) findViewById(R.id.imageView);
        // Call the transition
        TransitionDrawable drawable = (TransitionDrawable) picture.getDrawable();
        // Give it a time period
        drawable.startTransition(1500);


    }

    public void doubleTrouble (View myView){

        /* Now we will have one image slide off the screen
        * and another image slide into it's place. Note that one
        * of the images is offscreen in the on create methode below.
        */
        // Define the image views to use.
        ImageView firstPic = (ImageView) findViewById(R.id.imageView2);
        ImageView secondPic = (ImageView) findViewById(R.id.imageView3);
        // Set the alpha (not really needed here, was used in other exercises.
        // Used here to make them "dimmer" at half brightness.
        firstPic.setAlpha(0.5f);
        secondPic.setAlpha(0.5f);
        // Call the translation (movement) and set the duration.
        firstPic.animate().translationXBy(-1000f).setDuration(1500);
        secondPic.animate().translationXBy(-1000f).setDuration(1500);
    }

    public void spinner (View aView){
        // A simple trick to spin the image.
        // Define the image view to use.
        ImageView firstPic = (ImageView) findViewById(R.id.imageView2);
        // Rotate the image this many degrees in this much time.
        firstPic.animate().rotation(360f).setDuration(1500);

    }

    public void sizeMe (View badView){
        // A simple trick to "grow" an image.
        // Define the image view to use.
        ImageView borris = (ImageView) findViewById(R.id.imageView4);
        // Tell that image to animate to be twice it's size.
        borris.animate().scaleX(2.0f).scaleY(2.0f).setDuration(1500);

    }

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

        // Note that this image view is set off screen from the app start.
        // Define the image view to use.
        ImageView firstPic = (ImageView) findViewById(R.id.imageView2);
        // Set that view off screen.
        firstPic.setTranslationX(1000f);
    }
}

transition.xml

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/rocky" />
    <item android:drawable="@drawable/bull" />
</transition>

Hopefully that not only makes sense, but might help you move objects around the screen. This Android Developer Course is really well done. I highly recommend it.

Linux – keep it simple.

Rocky and Bullwinkle cross-fade app!

In my continued determination to complete the Android Developer course, I have been given yet another challenge by my instructor, which is to have two images, where one faded out, and the other faded in. This turned out to be really simple, but it did involve some Googling on my part.

What I found was two entirely different approaches to this. Again, the power of object oriented language is that there is really more than one was to skin the proverbial cat, or Android, in this case.

The first method, which is the method my instructor used (after completing the challenge, he shows how he would do it). That method was to have two images overlay each-other, and set the alpha to 0 and 1 (o% and 100% visibility) and have them change with the animation command.

The second method, which is what I found first, was to have an xml file that referenced both drawings and have them change with the transitiondrawable command.

For fun, I asked Rocky and Bullwinkle to help me put both together in one app, so you can see how each works. You can download the app here:

http://www.mediafire.com/file/787eb04013pxzvg/crossfade.apk

And here is the code:

mainactivity.java

package com.alaskalinuxuser.crossfade;

import android.graphics.drawable.TransitionDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.*;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {

    public void crossFade (View view){

        ImageView picture = (ImageView) findViewById(R.id.imageView);
        TransitionDrawable drawable = (TransitionDrawable) picture.getDrawable();
        drawable.startTransition(1500);


    }

    public void doubleTrouble (View myView){

        ImageView firstPic = (ImageView) findViewById(R.id.imageView2);
        ImageView secondPic = (ImageView) findViewById(R.id.imageView3);

        firstPic.setAlpha(0f);
        secondPic.setAlpha(1f);

        firstPic.animate().alpha(1f).setDuration(1500);
        secondPic.animate().alpha(0f).setDuration(1500);
    }

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

Activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    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="com.alaskalinuxuser.crossfade.MainActivity">

    <ImageView
        android:layout_width="200sp"
        android:layout_height="200sp"
        app:srcCompat="@drawable/transition"
        android:id="@+id/imageView"
        android:onClick="crossFade"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <ImageView
        android:layout_width="200sp"
        android:layout_height="200sp"
        app:srcCompat="@drawable/rocky"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:id="@+id/imageView2" />

    <ImageView
        android:layout_width="200sp"
        android:layout_height="200sp"
        app:srcCompat="@drawable/bull"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:id="@+id/imageView3"
        android:onClick="doubleTrouble" />
</RelativeLayout>

transitions.xml

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/rocky" />
    <item android:drawable="@drawable/bull" />
</transition>

They seem to have the same ultimate affect, but I see the plus to the transition.xml file, because I could add many more possible transitions in an easy method.

Linux – keep it simple.

Updated the S4Camera app!

As we spoke about last time, there were two problems with my custom S4 camera app:

  1. No way to stop the recording, you had to wait for the 1 or 3 minute timer to elapse.
  2. No audio was recorded.

Well, I haven’t fixed everything yet, but I was able to fix issue #1, stopping the recording. Essentially, I added a button which was invisible all of the time, unless you were recording. Once you start recording (still for 1 or 3 minutes), the stop recording button will become visible in the corner of the screen.

Pressing that stop recording button causes a super user command to be sent using pkill -2 to kill the screenrecord function. A -2 pkill command is the same as a ^c (control-c) command. That is a very nice command which tells it to wrap up and then stop, but do so now! I tried other pkill commands, which literally kill the process in a less than nice fashion, but when I do that, the video is not “ended” properly and becomes unreadable. This method allows the screenrecord function to properly close writing to the video so it is readable!

You can check out the changes and download the latest version on my Github:

https://github.com/alaskalinuxuser/S4camera_app

https://github.com/alaskalinuxuser/S4camera_app/commit/51f0934ee7eed612f1fd168e20b27afc148e6a17

Linux – keep it simple.

A special camera app for the Samsung Galaxy S4!

Recently I was fortunate enough to compile a working version of AOKP Nougat for the Samsung Galaxy S4 JFLTETMO/JFLTEXX phones (Praise God!). For the most part, it seems to work great. The only big issue is a problem with the camera.

It’s not that the camera doesn’t work. In fact it still takes wonderful pictures. What doesn’t work, however, is creating a video recording. Actually, it causes the camera app to crash just attempting to select video mode from the app. I tried several different apps, and they all produce the same results. So, I decided to do something about it.

I tried looking over the crash logs, and it just didn’t make enough sense for me to make changes to the device trees for the camera. But, I didn’t want to give up. Instead, I decided to make a custom camera app that would overcome these difficulties. By God’s grace, I was successful!

It is still a work in progress, but it works well enough for now. The actual command to open the camera and take a video just isn’t working, so I made a workaround. Instead, the camera app simply displays the camera on a surface view, and I leveraged root (su) permission to record that surface view to a file: /sdcard/Pictures/video.mp4. After the recording is complete, there is a command to rename the file the current time in milliseconds, so the user doesn’t have to worry about overwriting their just recorded video by making another recording.

There is a camera picture button, which allows you to take a picture. The picture is taken via the normal camera method, since that portion works correctly. To take a video, you can click on the 1m/3m icon to choose 1 minute or 3 minutes of video recording, then hit the record button. Once you press record, the icons disappear and only the camera view is displayed, as the surface view is being recorded.

There are currently two main problems:

  1. There is no way currently to stop the recording. You simply have to “wait it out”. After the 1 or 3 minutes that you chose are up, the icons re-appear and a pop-up informs you that it is done. If you exit the app at this time, your home screen will be recorded instead until the time expires.
  2. There is currently no audio. I am fairly new at Android app making, and this is a huge learning curve for me, so I have not gotten the audio figured out yet.

You can check it out on my Github if you would like to view the source, you are welcome to use or abuse the source code in any way that helps you with your own projects as well. The app is build-able in Android Studio.

https://github.com/alaskalinuxuser/S4camera_app

And, if you want to download the app, it is also located on that Github page.

Linux – keep it simple.

​Android number guessing game gets better!

Last post I made a number guessing game for Android. It is simple and short, but works well enough. However, my online course teacher pointed out a problem that was in my game.

If the user did not make any guess, but just clicked the guess button, then the app would crash. His challenge to the students was to fix this error, and, praise God, I did. The problem stems from parsing a double that is blank. So, after searching Google, i found some clues, and I edited the code like so:

[CODE]

public void takeGuess(View v)

{

EditText userGuess = (EditText) findViewById(R.id.myGuess);

if (userGuess.getText().toString().equals(“”)) {

Toast toast = Toast.makeText(getApplicationContext(), “Please enter a number!”, Toast.LENGTH_SHORT);

toast.setGravity(Gravity.CENTER_VERTICAL|Gravity.CENTER, 0, 0);

toast.show();

} else {

Double uGuess = Double.parseDouble(userGuess.getText().toString());

if (uGuess < hidRandom) {

Toast toast = Toas……

[/CODE]
Now when a user clicks the guess button, the game first checks for a blank field. If the input field is blank, then the game will tell them to enter a number first. If the input has a number, then the game parses the double for the number. Seems to work well enough.
On a side note, this allowed me to make an updated version of an app, so I had to search how to do that. It turned out to be really simple. All that you do is open the build.gradle file and edit these two lines:

 

versionCode 2

versionName "1.1"

 

If you want to play the improved version, you can download it here:

 

https://www.mediafire.com/download/flnbswbblwboo4o
Linux – keep it simple.