title: Android 4.0.x hangs or reboots on drop of an item within the same ListView
body: <h2>Purpose</h2>
  
  <p>I have implemented the "reorder items from a ListView" paradigm following the Android 3.0 Drag &amp; drop framework.</p>
  
  <h2>Issue</h2>
  
  <p>Seen on android 4.0.3 and 4.0.4. Not tested on other releases.</p>
  
  <p>Drag an item of the ListView and drop it after the last item of the ListView.
  The shadow box is cleared and the ListView invalidated. That is the nominal behaviour and happens 90% of the time.</p>
  
  <p>But for the remaining 10%, what happens is:</p>
  
  <ul>
  <li><strong>NB</strong>: all of the effects listed below are seen AFTER <code>onDrag(View, DragEvent)</code> has returned for <code>ACTION_DRAG_ENDED</code>, that is to say the entire drag &amp; drop process seems to be completed before the problems occur.</li>
  <li>the shadow box is displayed for a mere 10 seconds before disappearance. Calling <code>view.invalidate()</code> in <code>onDrag(View, DragEvent)</code> handler for <code>ACTION_DRAG_ENDED</code> will correct that but won't fix the hang or reboot problem (see below)</li>
  <li>some unusual traces in logcat:</li>
  </ul>
  
  <blockquote>
    <p>I/ViewRootImpl(  954): Reporting drop result: true I/InputQueue-JNI( 
    210): Sending finished signal for input channel 'drag (client)' since
    it is being unregistered while an input message is still in progress.
    I/InputQueue-JNI(  210): Ignoring finish signal on channel that is no
    longer registered. W/WindowManager(  210): Drag is in progress but
    there is no drag window handle. I/ViewRootImpl(  954): Reporting drop
    result: true</p>
  </blockquote>
  
  <ul>
  <li>on some device, Android hangs or reboots. It depends of the device but the effect is always the same.</li>
  </ul>
  
  <h2>Source code</h2>
  
  <pre><code>import android.annotation.SuppressLint;
  import android.app.ListActivity;
  import android.content.ClipData;
  import android.content.ClipDescription;
  import android.os.Bundle;
  import android.view.DragEvent;
  import android.view.View;
  import android.view.View.DragShadowBuilder;
  import android.widget.AdapterView;
  import android.widget.ArrayAdapter;
  import android.widget.ListView;
  
  public class TestReorderActivity extends ListActivity {
  
      @SuppressLint("NewApi")
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
  
          ListView listView = getListView();
          String[] listeStrings = { "France", "United States", "Russia" };
          listView.setAdapter(new ArrayAdapter&lt;String&gt;(this,
                  android.R.layout.simple_list_item_1, listeStrings));
  
          listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
  
              @Override
              public boolean onItemLongClick(AdapterView&lt;?&gt; adapter, View view,
                      int id, long position) {
                  ClipData data = ClipData.newPlainText(" ",
                          Long.toString(position));
  
                  DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(
                          view);
                  if (view.startDrag(data, shadowBuilder/*
                                                       * new
                                                       * MyDragShadowBuilder(view)
                                                       */, view, 0)) {
                      return true;
                  }
  
                  return false;
              }
  
          });
  
          listView.setOnDragListener(new ListView.OnDragListener() {
  
              @Override
              public boolean onDrag(View view, DragEvent event) {
                  final int action = event.getAction();
  
                  switch (action) {
                  case DragEvent.ACTION_DRAG_STARTED:
  
                      if (event.getClipDescription().hasMimeType(
                              ClipDescription.MIMETYPE_TEXT_PLAIN)) {
                          // accept drag
                          return true;
                      } else {
                          // reject drag
                          return false;
                      }
  
                  case DragEvent.ACTION_DRAG_ENTERED:
                      // entered drag
                      return true;
  
                  case DragEvent.ACTION_DRAG_LOCATION:
                      // location is returned as event.getX() and event.getY()
                      return true;
  
                  case DragEvent.ACTION_DRAG_EXITED:
                      // cancel drag.
                      return true;
  
                  case DragEvent.ACTION_DROP:
                      // item dropped
                      processDrop(event);
                      return true;
  
                  case DragEvent.ACTION_DRAG_ENDED:
                  default: // unknown case
                      return true;
                  }
              }
  
              private boolean processDrop(DragEvent event) {
                  ClipData data = event.getClipData();
                  if ((data != null) &amp;&amp; (data.getItemCount() &gt; 0)) {
                      ClipData.Item item = data.getItemAt(0);
                      CharSequence value = item.getText();
                      long position = Long.valueOf(value.toString());
  
                      int x = (int) event.getX();
                      int y = (int) event.getY();
  
                      ListView listView = getListView();
  
                      int newPosition = listView.pointToPosition(x, y);
                      if (newPosition &gt; ListView.INVALID_POSITION) {
  
                          swap(position, newPosition);
                          return true;
                      }
                  }
  
                  return false;
              }
  
          });
  
      }
  
      // swap(long, long) here
  }
  </code></pre>