Categories
discuss

In-App screen recording on android to capture 15 frames per second

After a lot of searching and days of experiments I haven’t found a straight-forward solution.

I’m developing an app that user will interact with a pet on the screen and i want to let him save it as video.

Is there any “simple” way to capture the screen of the app itself?

I found a workaround (to save some bitmaps every second and then pass them to an encoder) but it seems too heavy. I will happy even with a framerate of 15fps

It seems to be possible, i.e. there is a similar app that does this, its called “Talking Tom”

Answer

It really depends on the way you implement your “pet view”. Are you drawing on a Canvas? OpenGl ES? Normal Android view hierarchy?

Anyway, there is no magical “recordScreenToVideo()” like one of the comments said.

You need to:

  • Obtain bitmaps representing your “frames”.
    This depends on how you implement your view. If you draw yourself (Canvas or OpenGL), then save your raw pixel buffers as frames.
    If you use the normal view hierarchy, subclass Android’s onDraw and save the “frames” that you get on the canvas. The frequency of the system’s call to onDraw will be no less than the actual “framerate” of the screen. If needed, duplicate frames afterwards to supply a 15fps video.

  • Encode your frames. Seems like you already have a mechanism to do that, you just need it to be more efficient.

Ways you can optimize encoding:

  • Cache your bitmaps (frames) and encode afterwards. This will work
    only if your expected video will be relatively short, otherwise
    you’ll get out of storage.
  • Record only at the framerate that your app actually generates (depending on the way you draw) and use an encoder parameter to generate a 15fps video (without actually supplying 15 frames per second).
  • Adjust quality settings to current device. Can be done by performing a hidden CPU cycle test on app startup and defining some thresholds.
  • Encode only the most relevant portion of the screen.
  • Again, really depending on the way you implement – if you can save some “history data”, and then convert that to frames without having to do it in real time, that would be best.
    For example, “move”, “smile”, “change color” – or whatever your business logic is, since you didn’t elaborate on that. Your “generate movie” function will animate this history data as a frame sequence (without drawing to the screen) and then encode.

Hope that helps

Categories
discuss

Jackson JSON parser invalid utf-8 start byte

I’m trying to parse the following JSON and I keep getting a JsonParseException:

{
   "episodes":{
      "description":"Episode 3 – Oprah's Surprise Patrol from 1/20/04nTake a trip down memory lane and hear all your favorite episodes of The Oprah Winfrey Show from the last 25 seasons -- everyday on your radio!"
   }
}

also fails on the … in this JSON

{
   "episodes":{
      "description":"After 20 years in sports talk…he’s still the top dog!  Catch Christopher “Mad Dog” Russo weekday afternoons on Mad Dog Radio as he tells it like it is…Give the Doggie a call at 888-623-3646."
   }
}

Exception:

org.codehaus.jackson.JsonParseException: Invalid UTF-8 start byte 0x96
 at [Source: C:Json Test Filesepisodes.txt; line: 3, column: 33]
    at org.codehaus.jackson.JsonParser._constructError(JsonParser.java:1291)
    at org.codehaus.jackson.impl.JsonParserMinimalBase._reportError(JsonParserMinimalBase.java:385)
    at org.codehaus.jackson.impl.Utf8StreamParser._reportInvalidInitial(Utf8StreamParser.java:2236)
    at org.codehaus.jackson.impl.Utf8StreamParser._reportInvalidChar(Utf8StreamParser.java:2230)
    at org.codehaus.jackson.impl.Utf8StreamParser._finishString2(Utf8StreamParser.java:1467)
    at org.codehaus.jackson.impl.Utf8StreamParser._finishString(Utf8StreamParser.java:1394)
    at org.codehaus.jackson.impl.Utf8StreamParser.getText(Utf8StreamParser.java:113)
    at com.niveus.jackson.Main.parseEpisodes(Main.java:37)
    at com.niveus.jackson.Main.main(Main.java:13)

Code:

public class Main {
    public static void main(String [] args) {
        parseEpisodes("C:\Json Test Files\episodes.txt");
    }
    public static void parseEpisodes(String filename) {
        JsonFactory factory = new JsonFactory();
        JsonParser parser = null;
        String nameField = null;

        try {
            parser = factory.createJsonParser(new File(filename));

            parser.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
            parser.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);

            JsonToken token = parser.nextToken();
            nameField = parser.getText();
            String desc = null;

            while (token != JsonToken.END_OBJECT) {
                if (nameField.equals("episodes")) {
                    while (token != JsonToken.END_OBJECT) {
                        if (nameField.equals("description")) {
                            parser.nextToken();
                            desc = parser.getText();
                        }

                        token = parser.nextToken();
                        nameField = parser.getText();
                    }
                }

                token = parser.nextToken();
                nameField = parser.getText();
            }

            System.out.println(desc);
        }
        catch (JsonParseException e) {
            e.printStackTrace();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Answer

The character at column 33 is , and the reason this would be the byte 0x96 is that the file is physically encoded as Windows-1252. You need to save the file in UTF-8, windows-1252 is not a valid encoding for json. How to do this depends on what text editor you are using.

See JSON RFC:

  1. Encoding

    JSON text SHALL be encoded in Unicode. The default encoding is
    UTF-8.

Categories
discuss

Java Collections.sort() missing ConcurrentModificationException

I stumbled over this odd bug. Seems like Collections.sort() does not modify the sorted list in a way that enables a detection of concurrent modifications when also iterating over the same list. Example code:

    List<Integer> my_list = new ArrayList<Integer>();

    my_list.add(2);
    my_list.add(1);

    for (Integer num : my_list) {

        /*
         * print list
         */
        StringBuilder sb = new StringBuilder();
        for (Integer i : my_list)
            sb.append(i).append(",");
        System.out.println("List: " + sb.toString());

        /*
         * sort list
         */
        System.out.println("CurrentElement: " + num);
        Collections.sort(my_list);
    }

outputs

List: 2,1,
CurrentElement: 2
List: 1,2,
CurrentElement: 2

One would expect a ConcurrentModificationException, but it is not being raised and the code works although it shouldn’t.

Answer

Why would it throw ConcurrentModificationException when you are not adding/removing elements from your collection while iterating?

Note that ConcurrentModificationException would only occur when a new element is added in to your collection or remove from your collection while iterating. i.e., when your Collection is Structurally modified.

(Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)

sort wouldn’t structurally modify your Collection, all it does is modify the order. Below code would throw ConcurrentModificationException as it add’s an extra element into the collection while iterating.

for(Integer num : my_list) {
    my_list.add(12);
    }

If you look at the source of sort method in Collections class, its not throwing ConcurrentModificationException.

This implementation dumps the specified list into an array, sorts the array, and iterates over the list resetting each element from the corresponding position in the array. This avoids the n2 log(n) performance that would result from attempting to sort a linked list in place.

public static <T extends Comparable<? super T>> void sort(List<T> list) {
        Object[] a = list.toArray();
        Arrays.sort(a);
        ListIterator<T> i = list.listIterator();
        for (int j=0; j<a.length; j++) {
            i.next();
            i.set((T)a[j]);
        }
    }

Extract from the book java Generics and Collections:

The policy of the iterators for the Java 2 collections is to fail fast, as described in Section 11.1: every time they access the backing collection, they check it for structural modification (which, in general, means that elements have been added or removed from the collection). If they detect structural modification, they fail immediately, throwing ConcurrentModificationException rather than continuing to attempt to iterate over the modified collection with unpredictable results.

Categories
discuss

google maps not showing on android device

Android device only shows tiles for map. Seems to be widely reported. I followed the instructions of this link:

https://developers.google.com/maps/documentation/android/start

I did the following:

1) In Eclipse, I signed in Release Mode. I select File > Export. Selected Export Android Application, and clicked Next. Created a new keystore. Then uploaded the apk to google play.

2) Android app worked on device but map didnt show. It just showed tiles.

3) So I followed the instructions in the link above.

4) I located the keystore file that I created above. My keystore is called ziggy.keystore and alias is ziggy keystore.

5) I ran this in terminal on Mac OSX:

keytool -list -v -keystore ziggy.keystore -alias ziggy keystroke

6) The above command produces output that includes a line that contains the certificate’s SHA-1 fingerprint. The fingerprint is the sequence of 20 two-digit hexadecimal numbers separated by colons.

7) Now that I have the signing certificate fingerprint, I created a project for the application in the Google APIs Console. In a browser, I navigated to https://code.google.com/apis/console/

8) I clicked Create Project. I named it API project. I see a list of APIs and services in the main window.

9) I scroll down until I see Google Maps Android API v2. To the right of the entry, I clicked the switch indicator so that it is on. I agreed to the terms of service and clicked accept.

10) In the left navigation bar, I clicked API Access. In the resulting page, I clicked Create New Android Key. In the resulting dialog, I entered the SHA-1 fingerprint, then a semicolon, then the application’s package name.

11) I copied the API key. I opened my application’s manifest, contained in the file AndroidManifest.xml. And add the following element as a child of the element, by inserting it just before the closing tag :

<meta-data
    android:name="com.google.android.maps.v2.API_KEY"
    android:value="your_api_key"/>

* Note that I used my real api key.

12) I added this as well:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>


<permission
      android:name="com.otl.AndroidRemoteApp1.permission.MAPS_RECEIVE"
      android:protectionLevel="signature"/>
    <uses-permission android:name="com.otl.AndroidRemoteApp1.permission.MAPS_RECEIVE"/>

<uses-feature
android:glEsVersion="0x00020000"
android:required="true"/>    

13) Then in my ShowMapActivity.java:

    super.onCreate(savedInstanceState);
    setContentView(R.layout.show_map);
            mapView = (MapView) findViewById(R.id.mapview);

    myMapController = mapView.getController();  
    mapView.setBuiltInZoomControls(true);

    Drawable marker=getResources().getDrawable(android.R.drawable.star_big_on);
            ...

14) Then in my show_map.xml file:

<com.google.android.maps.MapView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mapview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clickable="true"
    android:state_enabled="true" 
    android:apiKey="my_api_key"
/>

* I replaced my_api_key with the real key.

So I followed all the instructions and then when I downloaded the app on an android device, it did not show the map. It just shows the tiles thing, which has been reported before.

I’m not sure what step I missed to get this to work.

Answer

The configuration steps looks good to me.

But i think you are interacting with the library in an old fashioned way. I know the documentation says that the MapView can be added and controlled to the Activities, but i would try to use the new GoogleMap and MapFragment approach. I’m not really sure how supported the “extending MapActivity and handling MapView” are on the V2 of the library

Here’s the documentation for it: https://developers.google.com/maps/documentation/android/map#add_a_map_to_an_android_application

Have you tried it?

Categories
discuss

ActionBar with navigation tabs changes height with screen orientation

My goal is to increase the ActionBar height for portrait mode. I currently set

android:actionBarSize

in my Themes.xml.

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <style name="DayTheme" parent="android:style/Theme.Holo.Light">
        <item name="android:actionBarSize">@dimen/actionBarHeight</item>
        <item name="android:actionBarTabTextStyle">@style/tab_indicator_text_dark</item>
    </style>
    <style name="NightTheme" parent="android:style/Theme.Holo">
        <item name="android:actionBarSize">@dimen/actionBarHeight</item>
        <item name="android:actionBarTabTextStyle">@style/tab_indicator_text_light</item>
    </style>
</resources>

I get the desired effect in landscape mode where I have increased the ActionBar height to 80dp.

enter image description here

However, went I rotate the screen into portrait mode the height changes like so.

enter image description here

Note I make the following calls in code.

final ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayShowTitleEnabled(false);
bar.setDisplayShowHomeEnabled(false);

I am developing on a Nexus 7 with android 4.2.

How do I get the same 80dp height in portrait mode that I have in landscape mode?

Answer

You wrote:

How do I get the same 80dp height in portrait mode that I have in landscape mode?

By setting both the Application theme attribute android:actionBarSize and the ActionBar.TabView style attribute android:minHeight (or height) to 80 dip.

A basic example:

<style name="ThemeHoloWithActionBar" parent="android:Theme.Holo.Light">
    <item name="android:actionBarTabStyle">@style/ActionBarTabStyle</item>
    <item name="android:actionBarSize">80dip</item>
</style>

<style name="ActionBarTabStyle" parent="@android:style/Widget.Holo.ActionBar.TabView">
    <item name="android:minHeight">80dip</item>
</style>

Set theme in Manifest:

   <application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/ThemeHoloWithActionBar" >

Add some tabs to the ActionBar in an Activity:

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

    ActionBar actionbar = getActionBar();
    actionbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    actionbar.setDisplayShowTitleEnabled(false);
    actionbar.setDisplayShowHomeEnabled(false);
    ActionBar.Tab tabA = actionbar.newTab().setText("Tab A");
    ActionBar.Tab tabB = actionbar.newTab().setText("Tab B");
    ActionBar.Tab tabC = actionbar.newTab().setText("Tab C");

    tabA.setTabListener(new MyTabsListener());
    tabB.setTabListener(new MyTabsListener());
    tabC.setTabListener(new MyTabsListener());

    actionbar.addTab(tabA);
    actionbar.addTab(tabB);
    actionbar.addTab(tabC);
}

This produces tabs with 80 dip height in portrait mode:

enter image description here

and tabs with 80 dip height in landscape mode:

enter image description here

EDIT:

For this example, SDK versions in the Manifest were set to:

android:minSdkVersion="12"
android:targetSdkVersion="15"

According to OP, the example works with these SDK settings. However, if targetSkdVersion is instead set to 16 or 17, the example doesn’t work. OP has filed a bug report:

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..