Fixing the status bar visible after photo roll showing bug on iOS7/iPad

In iOS7 disabling the status bar is a bit more complex than it was in iOS6. (We have to add a row call it “View controller-based status bar appearance” and set it to boolean NO in the Target Info properties tab.)

Unfortunately, there’s also a bug on the iPad (up to 7.1 as of this writing) that makes the status bar visible again after the photo roll is shown. Luckily, there’s a pretty easy fix.

First, make sure your UIViewController subclass (the one that is already a UIImagePickerControllerDelegate) is a UINavigationControllerDelegate as well. (It should be anyway to get rid of the warnings in XCode.) Then add the following UINavigationControllerDelegate function to that subclass:

- (void)navigationController:(UINavigationController *)navigationController
      willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    [[UIApplication sharedApplication] setStatusBarHidden:YES];
}

That’s it!

Selecting an enum value from an enum DropDownList in asp.net

If you ever want a user to be able to select from an enumerated dropdown list, and have been able to create the dropdown, but haven’t been able to figure out how to select the default value, it turns out to be relatively straight forward:

Somewhere you have an enum defined:

public enum MyEnum
{
  Enum1 = 1, Enum2 = 2, Enum3 = 3
}

Somewhere in a ViewModel, you use the enum:

  public MyEnum MyEnumVariable { get; set; }

You’d think you could use it and have the correct value selected with something like this:

@Html.DropDownListFor(m=>m.MyEnumVariable,Enum.GetNames(typeof(MyEnum)).ToArray()
     .Select(f=>new SelectListItem() { Text=f,Value=f,Selected=(f==m.MyEnumVariable.ToString()) }))

But unfortunately, that doesn’t work. You have to convert f into an enum, and compare them as enums:

@Html.DropDownListFor(m=>m.MyEnumVariable,Enum.GetNames(typeof(MyEnum)).ToArray()
     .Select(f=>new SelectListItem() { 
        Text=f,Value=f,Selected=((MyEnum)Enum.Parse(typeof(MyEnum),f))==m.MyEnumVariable }))

A bit more complicated, but works like a charm!

Debugging no-touch zones

When converting some iOS apps from iOS6 to iOS7, I came across a very strange bug. I had an app with tons of views and view controllers, and on the right side of the screen, touches wouldn’t be recognized. (For buttons, gestures, scrolling, etc.) It was quite obvious that one of the views frame’s wasn’t covering that part of the screen. The easy way to figure out which view it is is to add:

    self.view.clipsToBounds=true;

inside each viewDidLoad, verify that the dead zone is no longer visible, and then slowly remove the clipsToBounds calls one at a time until the dead zone is visible again, and you’ve found the offending view! Then take whatever steps you need to adjust that view properly.

In my case, a view had a frame (0,0+768,1024) for a landscape view. Changing this to (0,0+1024,768) resolved the issue. Oddly enough, either sized frame didn’t cause iOS6 to have issues, just iOS7.

Hiding the navigation bar shadows in iOS7

I had a doozy of a time trying to hide the tiny little one pixel high grey shadows in the navigation and tab bars. Google had a lot of suggestions, but none of them worked until I came up with a combination of a few that did the trick. In your application:didFinishLaunchingWithOptions: functions, add the following:

   [[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
   [[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];

This removes the shadow for all navigation bars and tab bars, so if you want a different behavior this probably won’t work.

Also make sure your navigation bar and tab bar don’t have translucency set. (There’s a checkbox in Interface Builder.)

Keeping your mobile screen active (iOS and Android)

There are times when you need to force your app to stay active. (For example, a routing app or something where its supposed to be hands free. You don’t want your user to have to keep tapping it to keep it from sleeping.) Its easy to do this in both Android and iOS.

For Android, insert this little bit of code in each Activity’s onResume() function that you want to prevent from sleeping:

	@Override
	public void onResume() {
		super.onResume();
		// stop screen from sleeping
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
	}

Android will re-enable sleep timeouts whenever you exit the app, so you don’t have to worry about turning it back on.

For iOS, its almost as simple, except you only have to do it once for your entire app. You enable it when your application becomes active, and disable it when it enters the background. Insert this bit of code in your app delegate:

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // stop screen from sleeping
    [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // let screen sleep
    [[UIApplication sharedApplication] setIdleTimerDisabled:NO];
}

That’s it!

Distributing and installing apk’s using MacOS and Eclipse

Once you’ve developed an android app, you’ll want to send it to beta testers and end customers. This is actually pretty painless once you know how.

Create a keystore file.

To make an apk file that they can install, you have to sign it, and in order to sign it, you first have to generate a keystore. Luckily the android sdk comes with the tool to do this. You can generate the keystore file with the keytool app:

    keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -validity 10000

Replace alias_name with the name you want to use for the key. The first 8 characters are used.

You will be asked for a password. This will be requested whenever you sign an apk file with this keystore, so be sure to remember it! It will ask a number of questions after. I’m not sure which ones are required, but since it helps your customers to know how to contact you, its best to put in as much information as you’re comfortable with. I generally use the same password for the alias.

This will a file called my-release-key.keystore which you will use when signing the app.

Creating a signed apk file.

Now that you have a keystore file, you can create a signed apk file. To do this, right click on the base of your application’s tree in Package Explorer, select the ‘Android Tools’ menu, and select ‘Export Signed Application Package…’ Select after confirming the project. Click on ‘Use Existing keystore’, and Browse to where you generated the keystore earlier, and select the keystore. You will need to enter the password you used for the keystore file, and then again for the alias. Finally, it will ask you for the path the the apk file. Once you’ve selected where you want it to go, click on ‘Finish’, and the signed apk is saved for you!

Distributing/installing the apk file.

This is the easy part. You can email this apk file, and android devices will recognize it as being installable. You can put it on a web server, and browse for it using the android device. If there’s a way the android device can see the file, then you should be able to install from that.

The device will probably ask you to change the security setting to allow you to install the apk because its not a known source.

Playing a full screen video in an android app the easy way.

The Android sdk has a MediaPlayer api that should make it easy to play videos. There is, however, a much easier way.

VideoView makes it super simple to play videos. Here’s how we use it.

The XML files

First, add a VideoView to the activities xml file. We’ll call it videoplayer.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <VideoView
        android:id="@+id/myvideoview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="center"
    />
</LinearLayout>

We set the LinearLayout to horizontal orientation in this case because my videos are all landscape. We set the layout’s to “fill_parent” so our VideoView takes up the whole parents view. We don’t want to stretch it out of proportion, but we do want the video centered, so we set the layout_gravity to “center”.

We also need to update the AndroidManifest.xml file to make sure our VideoPlayer activity is full screen (using theme), stays in landscape orientation (using screenOrientation) and only has one instance, so we don’t get a bunch of video players running. (launchMode)

    <activity
        android:name=".VideoPlayer" 
        android:label="@string/app_name"
        android:launchMode="singleTask"
        android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
        android:screenOrientation="landscape" ></activity>

Calling code

When we want to show a full screen video, we’ll do it by creating the intent for the VideoPlayer activity, grabbing the video resource id, pass it to the VideoPlayer activity, and start the activity:

private void playVideo(String resourceName) {
    Intent videoPlaybackActivity = new Intent(this, VideoPlayer.class);
    int res=this.getResources().getIdentifier(resourceName, "raw", getPackageName());
    videoPlaybackActivity.putExtra("fileRes", res);
    startActivity(videoPlaybackActivity);
}

The VideoPlayer Activity code

Now we can get to the VideoPlayer activity code. It turns out to be not that complex. Here’s VideoPlayer.java:

public class VideoPlayer extends Activity implements OnCompletionListener {
		   
    private VideoView mVV;
		 
    @Override
    public void onCreate(Bundle b) {
        super.onCreate(b);

        setContentView(R.layout.videoplayer);

        int fileRes=0;     
        Bundle e = getIntent().getExtras();
        if (e!=null) {
            fileRes = e.getInt("fileRes");
        }

        mVV = (VideoView)findViewById(R.id.myvideoview);
        mVV.setOnCompletionListener(this);
        mVV.setOnPreparedListener(this);
        mVV.setOnTouchListener(this);

        if (!playFileRes(fileRes)) return;

        mVV.start();
    }
		 
    private boolean playFileRes(int fileRes) {
        if (fileRes==0) {
            stopPlaying();
            return false;
        } else {
            mVV.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + fileRes));
            return true;
        }
    }

    public void stopPlaying() {
        mVV.stopPlayback();
        this.finish();		    	
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
        finish();
    }
}

It’s pretty simple. We set the VideoView’s video URI to point to the resource id passed (if it exists), and start playing. If it doesn’t exist, we exit.

Playing new video files

Since we added the singleLaunch taskMode to the activity, that means that if we attempt to launch the VideoPlayer activity while its still running, onCreate() won’t be called, so it won’t know that its supposed to be playing a different video. In this case, the onNewIntent() function will be called with the new intent. We simply parse the extras bundle to get the file resource, if any, and it will play the new file:

    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        int fileRes = 0;
        Bundle e = getIntent().getExtras();
        if (e != null) {
            fileRes = e.getInt("fileRes");
        }
        playFileRes(fileRes);
    }

Making the video loop

We would also like our video to loop until we stop it. The best place to do this is once the MediaPlayer has been prepared. We add OnPreparedListener to the implements list of the VideoPlayer activity, and a simple onPrepared function that simply sets our MediaPlayer instance to looping:

public class VideoPlayer extends Activity implements OnCompletionListener,OnPreparedListener {
...
    @Override
    public void onPrepared(MediaPlayer mp) {
        mp.setLooping(true);
    }
...
}

Stopping at a Touch

We would also like to be able to stop the video with a tap on the screen, so we add OnTouchListener to the implements list of the VideoPlayer activity, and a simple onTouch function that simply calls our stopPlaying() function:

public class VideoPlayer extends Activity implements OnCompletionListener,OnPreparedListener,OnTouchListener {
...
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        stopPlaying();
        return true;
    }
...
}

Complete Java Source

Here’s the complete source, in case you missed any additions:

public class VideoPlayer extends Activity implements OnCompletionListener,OnPreparedListener,OnTouchListener {
		   
    private VideoView mVV;
		 
    @Override
    public void onCreate(Bundle b) {
        super.onCreate(b);

        setContentView(R.layout.videoplayer);

        int fileRes=0;     
        Bundle e = getIntent().getExtras();
        if (e!=null) {
            fileRes = e.getInt("fileRes");
        }

        mVV = (VideoView)findViewById(R.id.myvideoview);
        mVV.setOnCompletionListener(this);
        mVV.setOnPreparedListener(this);
        mVV.setOnTouchListener(this);

        if (!playFileRes(fileRes)) return;

        mVV.start();
    }
		 
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        int fileRes = 0;
        Bundle e = getIntent().getExtras();
        if (e != null) {
            fileRes = e.getInt("fileRes");
        }
        playFileRes(fileRes);
    }
		    
    private boolean playFileRes(int fileRes) {
        if (fileRes==0) {
            stopPlaying();
            return false;
        } else {
            mVV.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + fileRes));
            return true;
        }
    }

    public void stopPlaying() {
        mVV.stopPlayback();
        this.finish();		    	
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
        finish();
    }
			
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        stopPlaying();
        return true;
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        mp.setLooping(true);
    }
}

Making a single-instance android app with Intents

If you have Intents that you want to react to in your android app, but you don’t want each new Intent to launch a new instance of your android app, you can make it single instance by adding the following to your main activity’s section in your AndroidManifest.xml:

  android:launchMode="singleInstance"

When you do this, instead of processing your intents in onCreate(), you process it in onNewIntent():

@Override
protected void onNewIntent(Intent intent) {
  // ... process the intent
}

No touches on bottom of iPhone 5 screen

If you ever convert an old project to work with the iPhone 5 (or future larger devices), you may encounter a situation where everything displays correctly on-screen, but for some reason, you’re not getting any touches in the lower 88 pixels. (The extra height of the iPhone 5 screen in X-Code.)

If you’re using a MainWindow.xib file, this is most likely caused because you haven’t selected ‘Full Screen At Launch’ for the Window, so it uses your original size for the window (480×640). (Even though it uses your original size for the window, the larger views will ‘leak’ and the entire screen will be filled, but any input on the lower section will be masked, so you won’t get events there.)