Android Lollipop: -505 Error for AIR Apps

Problem:

After upgrading to Android 5.0 (Lollipop), a number of my apps disappeared. Trying to re-install them from the market resulted in a -505 error. This problem is most common with cross-platform Adobe AIR apps, more specifically, apps signed with an SHA1 generation with some certificates. The upgrade to Lollipop doesn’t correctly translate these specific keystores. When the apps disappear, the mismatched keystore sits around in memory preventing the app from being re-installed.

This impacts some very high profile games and can also impact in app purchases. Since the root cause is with the certificate, this isn’t limited to AIR apps. Native apps are much less likely to be using one of these keystores but it may be worth testing either way. Instructions on how to validate your key: https://code.google.com/p/android/issues/detail?id=79089#c8

“You can run the following commands on the META-INF/CERT.RSA from your signed APK file to check if your key is affected by this issue:

> keytool -printcert -file CERT.RSA
> openssl pkcs7 -inform DER -in CERT.RSA -outform PEM -out CERT.PEM -print_certs
> keytool -printcert -file CERT.PEM

The two keytool commands print out the fingerprints. If they do not match, the key is affected by this issue.”

Solution:

The only solution I’ve seen is to manually uninstall each affected package via ADB. After doing that, I was able to re-install the apps directly from the market. Not exactly something an average user should be expected to do but it’s better than nothing. Let’s hope that Google is able to resolve this with an OS update in the near future.

Resources:

https://code.google.com/p/android/issues/detail?id=79089
http://stackoverflow.com/questions/27041575/android-lollipop-error-code-505-during-installation-app
https://code.google.com/p/android/issues/detail?id=79375
https://forums.adobe.com/message/6942812#6942812

Animation with an Android ScrollView

Extend the Android ScrollView class and override the onScrollChanged method to animate your content based on the users current scroll position.

In this example I’m making changes directly to the margin of all RelativeLayouts to prevent the views from going off screen when the user scrolls. This code could easily be made generic and applied to any scroll view with linear blocks of content.

    /**
     * This can be made more generic and added as an AnimationPattern of the scroll view.
     *
     * @param scrollView
     * @param x
     * @param y
     * @param oldx
     * @param oldy
     */
    @Override
    public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) {
        int yScroll = y;
        double percentScrolled = (double)scrollView.getScrollY() / (double)scrollView.getMaxScrollAmount();

        if(y < 0) {
            yScroll = 0;
            percentScrolled = 0;
        }

        int diff = (mScrollingContent.getBottom()-(scrollView.getHeight()+scrollView.getScrollY()+mScrollingContent.getTop()));// Calculate the scrolldiff
        if( diff <= 0 && atBottom) {
            return;
        } else if(diff <=0) {
            // if diff is zero, then the bottom has been reached, do one more pass
            Log.d("CurrentTempFragment", "MyScrollView: Bottom has been reached" );
            atBottom = true;
        }else {
            atBottom = false;
        }


        // Layouts are 170dp tall
        int layoutHeight = (int)(170.0 * (1.0 - percentScrolled));
        int shadowPadding = 20;
        layoutHeight = Math.max(layoutHeight, 70);

        if(layoutHeight != 70) {
            // All layouts have locked. Allow the last layout to finish scrolling up
            scrollCap = yScroll;
        }

        // TODO: Instead of using relative layouts, create a class that knows it's min / max size
        for(int i = 0; i < layouts.length; i++) {
            // Convert from int to dp
            int toHeight = getDPI(layoutHeight, metrics);
            int toTopMargin = scrollCap + getDPI(layoutHeight*i - shadowPadding*(i+1), metrics);
            if(i < layouts.length - 1) {
                updateLayout(layouts[i], toHeight, toTopMargin);
            }else {
                // Special case for the last layout, it's taller and doesn't re-size
                updateLayout(layouts[i], toTopMargin);
            }
        }

        // Animate the sun up based on scroll index
        int padding = Math.max(300,(int)(getDPI(400, metrics) * (0.85 - percentScrolled)));
        mSunIcon.setPadding(0,padding,0,0);
    }

    public void updateLayout(RelativeLayout layout, int layoutHeight, int layoutMargin) {
        RelativeLayout.LayoutParams head_params = (RelativeLayout.LayoutParams)layout.getLayoutParams();
        head_params.height = layoutHeight;
        head_params.setMargins(0, layoutMargin, 0, 0); //substitute parameters for left, top, right, bottom
        layout.setLayoutParams(head_params);
    }

    public void updateLayout(RelativeLayout layout, int layoutMargin) {
        RelativeLayout.LayoutParams head_params = (RelativeLayout.LayoutParams)layout.getLayoutParams();
        head_params.setMargins(0, layoutMargin, 0, 0); //substitute parameters for left, top, right, bottom
        layout.setLayoutParams(head_params);
    }

Full project source code can be found here:
https://github.com/blackcj/Temperature

Control an IR Device with a Spark Core

Reading from sensors is great but there are times when you need to interact with surrounding hardware. Window air conditioners, televisions, stereos and many other household electronics communicate with infra-red (IR). Adding an IR LED to your spark core will allow you to control these electronics remotely. For example, I’m currently using a temperature sensor along with an IR LED and Spark Core to turn my window AC unit on and off based on ambient temperature and time of day.

There are two types of IR LEDs 950nm and 850nm. The type of LED you’ll need will depend on the specific device you plan to control. You may want to pick up a couple of each type to be safe. We’ll use an IR receiver to read the IR code from the devices existing remote.

[Update 10/19/2014] A 330 ohm resistor should be used with a 5v power supply (Arduino boards). The Spark Core has a 3.3v output so you should use a 100 ohm resistor instead. Switching to a 100 ohm resistor resulted in much better range for the IR LED. [/Update]

For this example you’ll need:
- 950nm IR LED $0.95
- IR Receiver $1.95
- 100 ohm resistor 330 ohm resistor
- A Spark Core $39.00
- A soldering iron and solder
- An Arduino Board (optional)

Pro’s of IR LEDs:
- Cheap
- Easy to use
- Work with existing hardware

Con’s of IR LEDs:
- Requires physical proximity to the target device
- Signals are one directional (no feedback loop)

Pre-requisites:

Spark Core connected to your WIFI and ready to accept new sketches via the web interface. You should also be familiar with IR LEDs. There are plenty of tutorials available. In this example, we’ll be focused on the Spark Core specific hook up and code.

Step 1: Record Your IR Signal

Each button on your existing remote outputs a unique IR signal. Before you can send an IR signal with the Spark Core, you must first record that signal from your remote using the IR Receiver. I find it easier to use the serial output from a standard Arduino board (instead of the Spark Core). Record the raw signal from one of the buttons on your existing remote using this tutorial. Copy and paste the raw output, we’ll be using it later.

Step 2: Connect the IR LED to Your Spark Core

Use a 100 ohm resistor 330 ohm resistor. Connect the negative wire to the Spark Core ground. Connect the D3 pin to the 100 ohm resistor 330 ohm resistor and then to the positive wire of the LED.
Schematic diagram

Step 3: Add the IRremote Library

Qwertzguy ported the IRremote library from Arduino to Spark Core. You can find the library here. Add the .cpp and .h files to your Spark Core project using the + button in the top right corner of your project.

Example code.

Step 4: Write the Spark Core Code (IRremote.ino)

// This #include statement was automatically added by the Spark IDE.
#include "IRremote.h"

int commadDevice(String args);

IRsend irsend(D3); // hardwired to pin 3; use a transistor to drive the IR LED for maximal range

// Use the raw code you recorded from your device, in this example the length of the code is 37
unsigned int rawCodes[] = {8300, 4200, 450, 1650, 450, 1650, 450, 1650, 450, 600, 450, 1650, 450, 600, 450, 1650, 450, 1650, 450, 4250, 450, 1650, 450, 1650, 450, 600, 450, 1650, 450, 600, 450, 600, 450, 650, 450, 600, 500};

void setup()
{
  Spark.function("toggle", commadDevice);
}

int commadDevice(String args)
{
    int rawSize = sizeof(rawCodes)/sizeof(int); // In this example, rawSize would evaluate to 37
    irsend.sendRaw(rawCodes, rawSize, 38);
    return 1;
}

Flash the new sketch to your device.

Step 5: Command Your Device

# EXAMPLE REQUEST
curl https://api.spark.io/v1/devices/YOUR_DEVICE_ID/toggle \
     -d access_token=YOUR_ACCESS_TOKEN

Failed to Find Android Wearable Dependency

Problem:

After installing Android Studio Beta and using the wizard to create a new wearable app, the Gradle build failed with the following errors:

Error: Failed to find: com.google.android.gms:play-services-wearable:+
Error: Failed to find: com.google.android.support:wearable:+

Solution:

[Update]Additional useful information: http://developer.android.com/preview/google-play-services-wear.html[/Update]

[Update 7/16/14]The latest version of Android Studio extends Activity for watches rather than WatchActivity[/Update]

Until we get an official update, there is a work around I found on this site.

1. Open your Android SDK Manager.
2. Click on Tools -> Manage Add-on Sites… -> User Defined Site
3. Add https://dl-ssl.google.com/android/repository/addon-play-services-5.xml
4. Update your extras (Google Play Services and Google Repository)
5. Sync your project in Android Studio

Even after that, WatchActivity is still missing. Switching from WatchActivity to Activity seems to work but is probably not a good long term solution. Android Studio should now extend Activity instead of WatchActivity. If the wizard creates a project extending WatchActivity, update Android Studio. OK, now everything is building but the install fails for the emulator: Failure [INSTALL_FAILED_OLDER_SDK]

Changing the minSdkVersion, targetSdkVersion and compiledSdkVersion to 20 did the trick. Right now the watch system images are available at API 20 but the wizard sets everything up with ‘L’. Again, let’s hope this is resolved soon. Finally, I was able to get ‘Hello Round World!’ to show up on the emulator.

build.gradle in the wear folder

android {
    compileSdkVersion 20
    buildToolsVersion '20.0.0'
    defaultConfig {
        applicationId 'com.example.cblack.myapplication'
        minSdkVersion 20
        targetSdkVersion 20
        versionCode 1
        versionName '1.0'
    }
    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    productFlavors {
    }
}

Hopefully Google releases an update soon. I would expect another Android SDK Manager and Watch SDK update shortly that resolves these issues. I’m excited to start building apps for watches! Stay tuned for more wearable examples.