Searching an Array List

Searching an array list:

// When we click the search button.
public void searchACity (View searchView) {

    // Set our boolean to false.
    searchYes = false;

    // Defining an array of titles and urls.
    searchCityList = new ArrayList<String>();
    searchCityUrl = new ArrayList<String>();

    // Clear the lists, so we don't get duplicates.
    searchCityList.clear();
    searchCityUrl.clear();

    // Get our text and turn it into a string that is lowercase.
    String search = searchMyLocal.getText().toString().toLowerCase();

    // Testing only // Log.i("WJH", search);

    // Okay, now search the citylist for that string.
    for (int i = 0; i < cityList.size(); i++) {

        // If it contains the search string....
        if (cityList.get(i).contains(search)) {

            // Testing only // Log.i("WJH", cityList.get(i) + urlList.get(i));

            // Then add it to our new search lists.
            searchCityList.add(cityList.get(i));
            searchCityUrl.add(urlList.get(i));

            // And set our search boolean to true, because we found something.
            searchYes = true;

        }
    }

    // So, if we found something....
    if (searchYes) {

        // Clear the old lists.
        cityList.clear();
        urlList.clear();

        // For each item in our new search lists....
        for (int g = 0; g < searchCityList.size(); g++) {

            // Add them to our lists.
            cityList.add(searchCityList.get(g));
            urlList.add(searchCityUrl.get(g));

            // And notify of an update and update the list view.
            addaptedAray.notifyDataSetChanged();
            theList.invalidateViews();

        }

    } else { // But if nothing found....

        // The only way to see this, is if the search yielded no results.
        Toast.makeText(getApplicationContext(), "Nothing found that matches your search.", Toast.LENGTH_SHORT).show();

        // Reset the list
        addCities();

        // Update the list view.
        addaptedAray.notifyDataSetChanged();
        theList.invalidateViews();

    }

    // Get rid of the keyboard, so they can see the results...
    InputMethodManager imm = (InputMethodManager)getSystemService(getApplicationContext().INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(searchView.getWindowToken(), 0);

} // searchACity end.

In my Just Craigslist app, the user used to select their location from a list. I thought that was a good system when I made the app, because there is only one Craigslist city choice in my area. Once I chose my location, the preferences were saved in the app, so I never needed to change it.citysearch

However, it was pointed out to me that some people live close to two or more Craigslist areas, and have to search between these areas, constantly choosing another location. With the long list of places to choose from, this became very tedious.

So, I needed a way to search the list. Not only that, but I needed a way to re-list the searched passing criteria, and that is what I have done in the above code. Hopefully people will find that intuitive.

Essentially, I am taking the array lists that existed, and searching them with this line:

// If it contains the search string....
        if (cityList.get(i).contains(search)) {

Which I just looped through every city in the list, seeing if it contains the search criteria. If it does, then I add it to a temporary list. After the loop has finished searching, Android then clears the master list, and adds the temporary list to it, and refreshes the view, so now you can choose from your list of matching criteria. Ex: if you search for Georgia, you will be given a list of all the cities in Georgia that have a Craigslist area.

There were two problems:

  1. Case sensitive. The search is case sensitive. I solved this by forcing all queries to be lower case, and edited the city list to be all lower case as well. Even if they type in all caps, it will only search in lower case.
  2. No results. Some searches will naturally yield no results. Obviously, if you search for places on Mars or Saturn, you wont find them here on Earth, and certainly not in the Craigslist listings. So, when the search fails, you are given the original entire list again, as well as a popup to say that nothing was found.

It is my hope that this will make it easier for people to change locations. Only time will tell.

Linux – keep it simple.

Getting photos with intents on Android

During my class for app development, the instructor showed us how to get a photo from the phone’s gallery with intents. I wanted to take that one step farther, so I did. I also added getting a photo from the camera. To keep things small, I set the camera still to be returned as a thumbnail view, per the android instructions here:

https://developer.android.com/training/camera/photobasics.html

Here is what I have:

MainActivity.java

[CODE]

package com.example.alaskalinuxuser.photohowto;

import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {

    // Define our image view.
    ImageView myImage;

    @Override // On create, do this....
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Declare our image view.
        myImage = (ImageView)findViewById(R.id.imageView);

    }

    // If they click to choose a picture from the gallery....
    public void choosePic (View picView) {

        // Call the intent for the gallery.
        Intent i = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        // And start that intent for the result number 1.
        startActivityForResult(i, 1);

    }

    // If they click to take a picture button....
    public void takePic (View takeView) {

        // Call the intent for the camera.
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // And start that intent for the result number 2.
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
            startActivityForResult(takePictureIntent, 2);
        }

    }

    @Override // Listen for the results from intents.
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // If it is result number 1, and it was ok, and they chose something, then...
        if (requestCode == 1 && resultCode == RESULT_OK && data != null) {

            // Get the uri.
            Uri myChosenImage = data.getData();

            // Try in case it fails.
            try {

                // Make a bitmap from the uri.
                Bitmap myBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), myChosenImage);

                // Set our chosen image to the view.
                myImage.setImageBitmap(myBitmap);

                // Give a catch in case there is a problem.
            } catch (IOException e) {
                e.printStackTrace();
            }

            // But if it is result number 2, and it is okay, and there is data, then....
        } else if (requestCode == 2 && resultCode == RESULT_OK && data != null) {

            try { // In case it fails.

                // Get the extras (a small thumbnail in this case).
                Bundle extras = data.getExtras();
                // Set our bitmap to that extra.
                Bitmap camImage = (Bitmap) extras.get("data");
                // Set our image with that bitmap.
                myImage.setImageBitmap(camImage);
                // A catch in case it fails.
            } catch (Exception e) {
                e.printStackTrace();
            }

        }


    }
}

[/CODE]

 

Pretty neat, huh? You can check this out on my GitHub under the small apps repository.

Linux – keep it simple.

fatal error: ‘liblights/samsung_lights_helper.h’ file not found

Moving on from the S4, I began work on the Note Edge, only to be greeted with this error:

[CODE]
target thumb C: lights.APQ8084 <= hardware/samsung/liblights/lights.c
hardware/samsung/liblights/lights.c:34:10: fatal error: ‘liblights/samsung_lights_helper.h’ file not found
#include <liblights/samsung_lights_helper.h>
^
1 error generated.
[/CODE]

The fix was easy enough, I checked the folder, and sure enough, it was not there. So, I downloaded it from here:

https://github.com/LineageOS/android_hardware_samsung/tree/310d1999e5478a28b73eacbc5b4db62174431ee9/liblights

I like simple problems!

Linux – keep it simple.

Yet again, error: package com.android.okhttp does not exist

By now, I think I would remember this one by heart, yet every time, this error throws me for a loop….

[CODE]
external/apache-http/../../frameworks/base/core/java/android/net/http/SslCertificate.java:19: error: cannot find symbol
import com.android.internal.util.HexDump;
^
symbol: class HexDump
location: package com.android.internal.util
external/apache-http/../../frameworks/base/core/java/android/net/http/SslCertificate.java:42: error: package com.android.org.bouncycastle.asn1.x509 does not exist
import com.android.org.bouncycastle.asn1.x509.X509Name;
^
external/apache-http/../../frameworks/base/core/java/android/net/http/HttpResponseCache.java:19: error: package com.android.okhttp does not exist
import com.android.okhttp.Cache;
^
external/apache-http/../../frameworks/base/core/java/android/net/http/HttpResponseCache.java:20: error: package com.android.okhttp does not exist
import com.android.okhttp.AndroidShimResponseCache;
^
external/apache-http/../../frameworks/base/core/java/android/net/http/HttpResponseCache.java:21: error: package com.android.okhttp does not exist
import com.android.okhttp.OkCacheContainer;
^
external/apache-http/../../frameworks/base/core/java/android/net/http/HttpResponseCache.java:152: error: cannot find symbol
public final class HttpResponseCache extends ResponseCache implements Closeable, OkCacheContainer {/home/alaskalinuxuser/compile/20170314_AOKP7/prebuilts/tools/common/m2/repository/com/squareup/okhttp/okhttp/2.5.0
^
symbol: class OkCacheContainer
external/apache-http/../../frameworks/base/core/java/android/net/http/HttpResponseCache.java:154: error: cannot find symbol
private final AndroidShimResponseCache delegate;
^
symbol: class AndroidShimResponseCache
location: class HttpResponseCache
external/apache-http/../../frameworks/base/core/java/android/net/http/HttpResponseCache.java:156: error: cannot find symbol
private HttpResponseCache(AndroidShimResponseCache delegate) {
^
symbol: class AndroidShimResponseCache
location: class HttpResponseCache
external/apache-http/../../frameworks/base/core/java/android/net/http/HttpResponseCache.java:296: error: cannot find symbol
public Cache getCache() {
^
symbol: class Cache
location: class HttpResponseCache
[/CODE]

And, from the same website that I fail to bookmark every time:

https://issuetracker.google.com/issues/37130763

These are caused by missing some package dependency. Following patch is used to fix it (for external/apache-http/Android.mk):

— a/Android.mk
+++ b/Android.mk
@@ -95,7 +95,7 @@ LOCAL_SRC_FILES += \
../../frameworks/base/core/java/android/net/http/SslError.java \

-LOCAL_JAVA_LIBRARIES := $(apache_http_java_libs)
+LOCAL_JAVA_LIBRARIES := $(apache_http_java_libs) okhttp bouncycastle framework
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src \
$(LOCAL_PATH)/android \

That’s it. Those few ines make the whole thing work. Hopefully, I’m saving someone else from scouring the internet for this problem. Again.

Linux – keep it simple.

SyntaxError: invalid syntax

As I was wrapping up my work on the upgrade to 7.1.2 on the S4, I ran into this error, which prevented the compiler from building the userdata.img file. Here’s the output:

[CODE]
get/product/jfltetmo/userdata.img
File “./build/tools/releasetools/build_image.py”, line 157
print cmd
^
SyntaxError: invalid syntax
[/CODE]

The fix was actually quite easy. I needed to encapsulate the cmd in parenthesis, like this:

./build/tools/releasetools/build_image.py

[CODE]
cmd = “fec -e -p %d %s %s %s” % (padding_size, sparse_image_path,
verity_path, verity_fec_path)
print (cmd) # WJH
status, output = commands.getstatusoutput(cmd)
[/CODE]

The proof is in the pudding, but what help was how the cmd is defined, then notice that the “status, output” line also puts cmd in parenthesis. So, I did the same for the print cmd line, and it worked!

Linux – keep it simple.

Healthd problems with pointers to fonts….

In the continuing saga of updating to 7.1.2, I’ve run into an interesting error about gr_text and gr_measure that are used to set the fonts properly when you are charging your phone while it is off. In 7.1.1, this worked just fine:

AOKP711/system/core/healthd/healthd_mode_charger.cpp

[CODE]
static int draw_text(const char *str, int x, int y)
{
int str_len_px = gr_measure(str);

if (x < 0)
x = (gr_fb_width() – str_len_px) / 2;
if (y < 0)
y = (gr_fb_height() – char_height) / 2;
gr_text(x, y, str, 0);

return y + char_height;
———- Abreviated for space ——————–
gr_init();
gr_font_size(&char_width, &char_height);

#ifndef CHARGER_DISABLE_INIT_BLANK
[/CODE]

But that didn’t work in 7.1.2. I found this github commit for a sony phone: https://github.com/sonyxperiadev/device-sony-common/pull/247 and was able to modify it enough to fix the S4, like so:

AOKP712/system/core/healthd/healthd_mode_charger.cpp

[CODE]
static int draw_text(const char *str, int x, int y)
{
int str_len_px = gr_measure(gr_sys_font(), str); // WJH

if (x < 0)
x = (gr_fb_width() – str_len_px) / 2;
if (y < 0)
y = (gr_fb_height() – char_height) / 2;
gr_text(gr_sys_font(), x, y, str, 0); // WJH

return y + char_height;
———- Abreviated for space ——————–
gr_init();
gr_font_size(gr_sys_font(), &char_width, &char_height); //WJH

#ifndef CHARGER_DISABLE_INIT_BLANK
[/CODE]

It even worked! Hopefully that can help someone else out as well.

Linux – keep it simple.

 

CID_PATH not defined!

In an attempt to update the AOKP 7.1.1 rom for the Samsung Galaxy S4 to 7.1.2, I received an error about AOKP712/hardware/libhardware_legacy/wifi/wifi.c:179.18. The error complained that the CID_PATH was not defined, declared, or was not known.

Obviously, it was supposed to be declared somewhere, and I had two choices, declare it, or replace it with the actual path. I did the latter. Here is the old file:

[CODE]
#ifdef SAMSUNG_WIFI
char* get_samsung_wifi_type()
{
char buf[10];
int fd = open(CID_PATH, O_RDONLY);
if (fd < 0)
return NULL;
[/CODE]

And here is the new file changes:

[CODE]
#ifdef SAMSUNG_WIFI
char* get_samsung_wifi_type()
{
char buf[10];
int fd = open(“/data/.cid.info”, O_RDONLY); // WJH
if (fd < 0)
return NULL;
[/CODE]

And, to God be the glory, it works! One error down, only dozens to go!

Linux – keep it simple.

WebViews for dummies like me.

In my Android Developer Course, the instructor showed us how to create webviews and dataviews. I wanted to take that one step farther, so I made this app, which can switch between a dataview and a webview. You can download it here, just click on the floating button to switch between the views:

http://www.mediafire.com/file/d8x9yc4ykn7943v/Webviewfordummieslikeme.apk

Currently, for a webview, it goes to my website, right here. For a data view, I just threw together a few lines of HTML code and slapped it in there. But, here are a few great little tidbits about the program for those who are new like me, and need help figuring out what to do.

MainActivity.java

/* 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.webviewsfordummies;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends AppCompatActivity {

// Declare your webview …
WebView myWebView;
// Declare our boolean for switching.
Boolean webViewTrue;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

// Set our boolean to true, as we are displaying a website first.
webViewTrue = true;

// To identify my webview that I am going to put the website or data on.
myWebView = (WebView)findViewById(R.id.myWebView);

// To enable javascript.
myWebView.getSettings().setJavaScriptEnabled(true);

// To keep it here in our mini webview browser
myWebView.setWebViewClient(new WebViewClient());

// To load which webpage, in this case, mine.
myWebView.loadUrl(“https://thealaskalinuxuser.wordpress.com&#8221;);

// So, by clicking on the FAB, you can swap between webview and dataview.
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, “Switched between webview and dataview.”, Snackbar.LENGTH_LONG)
.setAction(“Action”, null).show();

// If we are in webview mode.
if (webViewTrue) {

// Then switch to dataview mode.
webViewTrue = false;

// You can load any data you make, you just need data, type, and encoding.
String myEncoding = “UTF-8”;
String myType = “text/html”;
String myData = “<html><body><h1>Check this out!</h1><p>This is just demonstrating how to load your own ‘data’.</p><h2>More info!</h2><p>Feel free to test this out with some code edits.</p></body></html>”;

// And pass that to our webview.
myWebView.loadData(myData, myType, myEncoding);

// Else, if you are in dataview, switch to web view.
} else {

// Set our boolean back to true.
webViewTrue = true;

// To load which webpage, in this case, mine.
myWebView.loadUrl(“https://thealaskalinuxuser.wordpress.com&#8221;);

}

}
});
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.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();

//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}

return super.onOptionsItemSelected(item);
}
}
The key parts here are these:

// If we are in webview mode.
if (webViewTrue) {

// Then switch to dataview mode.
webViewTrue = false;

// You can load any data you make, you just need data, type, and encoding.
String myEncoding = “UTF-8”;
String myType = “text/html”;
String myData = “<html><body><h1>Check this out!</h1><p>This is just demonstrating how to load your own ‘data’.</p><h2>More info!</h2><p>Feel free to test this out with some code edits.</p></body></html>”;

// And pass that to our webview.
myWebView.loadData(myData, myType, myEncoding);

// Else, if you are in dataview, switch to web view.
} else {

// Set our boolean back to true.
webViewTrue = true;

// To load which webpage, in this case, mine.
myWebView.loadUrl(“https://thealaskalinuxuser.wordpress.com&#8221;);

}

If you are in a webview, it switches to a dataview, and vice versa. But the thing I wanted to point out is the use of the String variables (myEncoding, myType, myData) which here I just set statically, but you could have some app that when the user clicks something, it fills in these variables, which in turn, when you load the data, it now has some pertinent information. Just food for thought. Praise God, it even works!

Linux – keep it simple.