Creating Categorized Views

Create categories so that Workflow applications and messages appear in lists under a category heading.

The comment tag associated with creating categorized views is ANDROID_CUSTOMIZATION_POINT_CATEGORIZEDVIEWS.

First, determine names for the categories. Sybase recommends that you name the final category “Miscellaneous;” this adds all applications and messages that do not match a category to the Miscellaneous category. Also in this example, all applications that belong to a category must include the category name contained in their display name. For example, an application named “Financial Claim” belongs in the “Financial” category.

There are other ways to determine categories; if you know the names of the applications in advance, you can simply list all the application names that belong in each category.

  1. Create a new XML layout called category.xml and paste the following code into the auto generated file:
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:padding="6dip">
    
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="0dip"
    android:layout_weight="1"
    android:layout_height="fill_parent">
    <TextView
    android:id="@+id/category"
    android:layout_width="fill_parent"
    android:layout_height="0dip"
    android:layout_weight="1"
    android:singleLine="true"
    android:ellipsize="marquee"
    android:gravity="center_vertical"
    />
    </LinearLayout>
    
    </LinearLayout>
  2. Copy the UiHybridAppScreen.java file and rename it to your own class, for example, CategorizedAppScreen.java, and open it for editing.
  3. Add the list of categories to the UiHybridAppScreen class, as a public static final member variable:
    public static final String[] m_asHybridAppCategories = { "Financial", "Utilities", "Miscellaneous" };
  4. Replace the HybridAppAdapter class with:
    private class HybridAppAdapter extends ArrayAdapter<Object>
          {
            private String[] m_asCategories;
             
             public HybridAppAdapter( Context context, int textviewResourceId, List<Object> items, String[] categories ){
               super( context, textviewResourceId, items );
               
               m_asCategories = categories;
               
               for( int index = 0; index < m_asCategories.length; index++ )
               {
                 this.add( m_asCategories[index] );
               }
             }
    
             @Override
             public View getView(int position, View convertView, ViewGroup parent)
             {     
               Object oObject = this.getItem(position);
               View v = null;
               if( oObject instanceof HybridApp )
               {
                 HybridApp oHybridApp = ( HybridApp ) oObject;
                   LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                      v = vi.inflate(R.layout.workflows, null);
                   
                   if ( oHybridApp != null ) 
                   {
                      ImageView ic = (ImageView) v.findViewById( R.id.workflow_icon );
                      ic.setImageResource( UiIconIndexLookup.getNormalIconIdForIndex( oHybridApp.getIconIndex() ));
                      TextView tt = (TextView) v.findViewById(R.id.workflow_title);
                      if (tt != null) {
                         tt.setText( oHybridApp.getDisplayName());
                      }
                   }
               }
               else
               {  //This position is not a HybridApp, but a category heading
                 String sString = ( String ) oObject;
                  LayoutInflater vi = ( LayoutInflater ) getSystemService( Context.LAYOUT_INFLATER_SERVICE );
                  v = vi.inflate( R.layout.category, null );
                  if( sString != null )
                  {
                     TextView tt = (TextView) v.findViewById( R.id.category );
                     if ( tt != null )
                     {
                        tt.setText( sString );
                     }
                  }
               }
               return v;
             }
             
             public void remove( HybridApp oApp )
             {
                // The object to remove has a different pointer
                // so match it up with the one in the list
                for ( int i = 0; i < this.getCount(); i++ )
                {
                  Object oObject = getItem( i );
                  if( oObject instanceof HybridApp )
                  {
                      HybridApp oTemp = ( HybridApp ) oObject;
                   
                      if ( oApp.getModuleId() == oTemp.getModuleId()
                            && oApp.getVersion() == oTemp.getVersion() )
                      {
                            super.remove( oTemp );
                         return;
                      }
                  }
                   
                }
             }
             
    
             public void sort()
             {
                // Sorts applications by name
                this.sort( new Comparator<Object>()
                {
                   @Override
                   public int compare( Object oObject1, Object oObject2 )
                   {
                     if( oObject1 instanceof String && oObject2 instanceof String)
                     {
                       String sString1 = ( String ) oObject1;
                       String sString2 = ( String ) oObject2;
                       for( int index = 0; index < m_asCategories.length; index++ )
                        {
                            if( sString1.equals( m_asCategories[index] ) )
                            {
                               return -1;
                            }
                            if( sString2.equals( m_asCategories[index]) )
                            {
                               return 1;
                            }
                        } 
                     
                     }
                     else if( oObject1 instanceof HybridApp && oObject2 instanceof HybridApp )
                     {
                       HybridApp oHybridApp1 = ( HybridApp ) oObject1;
                       HybridApp oHybridApp2 = ( HybridApp ) oObject2;
                       
                       int iCategoryIndex1 = getCategoryIndex( oHybridApp1 );
                       int iCategoryIndex2 = getCategoryIndex( oHybridApp2 );
                       
                       if( iCategoryIndex1 == iCategoryIndex2 )
                       {
                         return oHybridApp1.getDisplayName().toLowerCase().compareTo( oHybridApp2.getDisplayName().toLowerCase() );
                       }
                       else
                       {
                         return iCategoryIndex1 - iCategoryIndex2;
                       }
                     }
                     else
                     {  //we have one String (category heading) and one HybridApp
                       HybridApp oHybridApp = null;
                       String sString = null;
                       int iSwitch = 1;
                       if( oObject1 instanceof HybridApp)
                       {
                         oHybridApp = ( HybridApp ) oObject1;
                         sString = ( String ) oObject2;
                       }
                       else
                       {
                         oHybridApp = ( HybridApp ) oObject2;
                         sString = ( String ) oObject1;
                         iSwitch = -1;
                       }
                       
                       int iHybridAppCategoryIndex = getCategoryIndex( oHybridApp );
                       int iCategoryIndex = getCategoryIndex( sString );
                       if( iCategoryIndex <= iHybridAppCategoryIndex )
                       {
                          return 1*iSwitch;
                       }
                       else
                       {
                         return -1*iSwitch;
                       }
                       
                     }
                     
                      return 0;
                   }
                   
                   private int getCategoryIndex( String sString )
                   {
                     for( int index = 0; index < m_asCategories.length; index++ )
                      {
                         if( m_asCategories[index].equalsIgnoreCase( sString ) )
                         {
                            return index;
                         }
                      }
                      return m_asCategories.length - 1;
                   }
                   
                   private int getCategoryIndex( HybridApp oHybridApp )
                   {
                     for( int index = 0; index < m_asCategories.length; index++ )
                     {
                        if( oHybridApp.getDisplayName().toLowerCase().indexOf( m_asCategories[index].toLowerCase() ) >= 0 )
                        {
                           return index;
                        }
                     }
                     return m_asCategories.length - 1;
                   }
                });
             }
          }
  5. In the onResume method, make modifications to the following line (changes are shown in bold):
    this.m_adapter = new HybridAppAdapter( this, R.layout.workflows, 
    new ArrayList<Object>(Arrays.asList( HybridAppDb.getInvocableHybridApps() ) ), m_asHybridAppCategories );
    
  6. Modify the onListItemClick method as shown in the example code (changes are shown in bold):
    public void onListItemClick(ListView  oParent, View  v, int iPos, long id )
    {
       Object oObject = m_adapter.getItem( iPos );
       if( oObject instanceof HybridApp )
       {
          HybridApp oHybridApp = ( HybridApp ) oObject;
          Intent oIntentHybridAppContainer =  new Intent( this, UiHybridAppContainer.class );
          oIntentHybridAppContainer.putExtra( Consts.INTENT_PARAM_WORKFLOW_START_MODE, Consts.START_MODE_WORKFLOW );
          oIntentHybridAppContainer.putExtra( Consts.INTENT_PARAM_WORKFLOW_ID, ((HybridAppDb) oHybridApp).getHybridAppId() );
          oIntentHybridAppContainer.putExtra( Consts.INTENT_PARAM_WORKFLOW_PROGRESS_TEXT, oHybridApp.getDisplayName() );
          startActivityForResult( oIntentHybridAppContainer, Consts.INTENT_ID_WORKFLOW_CONTAINER );
       }
    }
    
  7. Save the file.
  8. Open the UiHybridAppMessagesScreen.java file for editing, and in the onCreateContextMenu method, make these modifications (changes are shown in bold):
    public void onCreateContextMenu( ContextMenu oMenu, View v, ContextMenu.ContextMenuInfo menuInfo)
          {
             super.onCreateContextMenu( oMenu, v, menuInfo );
    
             AdapterContextMenuInfo oInfo = (AdapterContextMenuInfo) menuInfo;
             Object oObject = m_adapter.getItem( oInfo.position );
             if( oObject instanceof Message )
             {
                Message oMsg = ( Message ) oObject;
             
                oMenu.setHeaderTitle( oMsg.getSubject() );
                oMenu.add( 0, CONTEXT_MENU_DELETE, 0, R.string.Context_Menu_Delete );
             
                // Save the id for operations used in the context menu
                m_iContextMessageId = oMsg.getMessageId();
             }
          }   
    
  9. In the onContextItemSelected method, make these modifications (changes are shown in bold):
    public boolean onContextItemSelected( MenuItem oItem )
          {
             if ( oItem.getItemId() == CONTEXT_MENU_DELETE )
             {
                AdapterContextMenuInfo oInfo = (AdapterContextMenuInfo) oItem.getMenuInfo();
    
                // The message might have been deleted while the context menu was open.
                // Make sure the position is still present and matches the id we expect
                if ( oInfo.position < m_adapter.getCount() )
                {
                   Object oObject = m_adapter.getItem( oInfo.position );
                   if( oObject instanceof Message )
                   {
                      Message oMsg = ( Message ) oObject;
                   
                      if ( oMsg.getMessageId() == m_iContextMessageId )
                      {
                         // Remove message from database
                         MessageDb.delete( oMsg.getMessageId() );
                      }
                   }
                }
                return true;
             }
             return false;
    
          }
    
  10. Replace the MessageAdapter class:
    private class MessageAdapter extends ArrayAdapter<Object>
          {
            String[] m_asCategories;
             
             public MessageAdapter( Context context, int textviewResourceId, ArrayList<Object> items, String[] categories ){
                super( context, textviewResourceId, items );
                
                m_asCategories = categories;
               
              for( int index = 0; index < m_asCategories.length; index++ )
              {
                 this.add( m_asCategories[index] );
              }
             }
    
              @Override
               public View getView(int position, View convertView, ViewGroup parent) {
                 Object oObject = getItem( position );
                 View v = null;
                 if( oObject instanceof Message )
                 {
                       Message oMsg = (Message) oObject;
                       LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                       v = vi.inflate(R.layout.workflowmessages, null);
                       
                       if ( oMsg != null )
                       {
                          //set the workflow message priority icon
                          ImageView imageForPriority = (ImageView) v.findViewById( R.id.priority_icon );
    
                          if ( oMsg.getMailPriority() == AmpConsts.EMAIL_STATUS_IMPORTANCE_HIGH )
                          {
                             imageForPriority.setImageResource( R.drawable.readhi );
                             imageForPriority.setVisibility( View.VISIBLE );
                          }
                          else if ( oMsg.getMailPriority() == AmpConsts.EMAIL_STATUS_IMPORTANCE_LOW )
                          {
                             imageForPriority.setImageResource( R.drawable.readlow );
                             imageForPriority.setVisibility( View.VISIBLE );
                          }
                          else
                             imageForPriority.setVisibility( View.GONE );
    
                           ImageView ic = (ImageView) v.findViewById( R.id.msg_icon );
                           if ( oMsg.isMsgProcessed() )
                              ic.setImageResource( UiIconIndexLookup.getProcessedIconIdForIndex( oMsg.getIconIndex()));
                           else
                              ic.setImageResource( UiIconIndexLookup.getNormalIconIdForIndex( oMsg.getIconIndex()));
                             TextView tf = (TextView) v.findViewById(R.id.msg_from);
                            TextView tt = (TextView) v.findViewById(R.id.msg_title);
                            TextView bt = (TextView) v.findViewById(R.id.msg_datetime);
                            if ( tf != null ) {
                               tf.setText( oMsg.getMsgFrom() );
                            }
                            if (tt != null) {
                                  tt.setText( oMsg.getSubject());
                            }
                            if(bt != null){
                               Calendar dtReceived = Calendar.getInstance();
                               dtReceived.setTime( oMsg.getReceivedDate() );
    
                               Calendar dtNow = Calendar.getInstance();
    
                               if ( dtNow.get( Calendar.YEAR ) == dtReceived.get(  Calendar.YEAR ) &&
                                     dtNow.get( Calendar.MONTH ) == dtReceived.get(  Calendar.MONTH ) &&
                                     dtNow.get( Calendar.DAY_OF_MONTH ) == dtReceived.get(  Calendar.DAY_OF_MONTH ) )
                               {
                                  bt.setText( ( new SimpleDateFormat( "hh:mm a" ) ).format( oMsg.getReceivedDate() ) );
                               }
                               else {
                                  bt.setText( ( new SimpleDateFormat( "MM/dd/yy" ) ).format( oMsg.getReceivedDate() ) );
                               }
                            }
    
                            // Update appearance unread messages
                            if ( tf != null && tt != null && bt != null )
                            {
                               if ( !oMsg.isMsgRead() )
                               {
                                  // Setup view for unread message
                                  v.setBackgroundResource(  R.drawable.unread_selector );
                                  
                                  tf.setTextColor( Color.WHITE );
                                  tf.setTypeface( null, Typeface.BOLD );
                               }
                               else
                               {
                                  // Setup view for read message
                                  v.setBackgroundResource( 0 );
                                  
                                  TypedValue tv = new TypedValue();
                                  getTheme().resolveAttribute( android.R.attr.textColorSecondary, tv, true );
                                  
                                  tf.setTextColor( getResources().getColor( tv.resourceId ) );
                                  tf.setTypeface( null, Typeface.NORMAL );
                               }
                            }
                       }
                  }
                  else
                  {
                     String sString = ( String ) oObject;
                    LayoutInflater vi = ( LayoutInflater ) getSystemService( Context.LAYOUT_INFLATER_SERVICE );
                    v = vi.inflate( R.layout.category, null );
                    if( sString != null )
                    {
                       TextView tt = (TextView) v.findViewById( R.id.category );
                       if ( tt != null )
                       {
                          tt.setText( sString );
                       }
                    }
                  }
                  return v;
               }
    
              public void sort()
              {
                 // Sorts applications by name
                 this.sort( new Comparator<Object>()
                 {
                    @Override
                    public int compare( Object oObject1, Object oObject2 )
                    {
                      if( oObject1 instanceof String && oObject2 instanceof String)
                      {
                        String sString1 = ( String ) oObject1;
                        String sString2 = ( String ) oObject2;
                        for( int index = 0; index < m_asCategories.length; index++ )
                         {
                             if( sString1.equals( m_asCategories[index] ) )
                             {
                                return -1;
                             }
                             if( sString2.equals( m_asCategories[index]) )
                             {
                                return 1;
                             }
                         } 
                      
                      }
                      else if( oObject1 instanceof Message && oObject2 instanceof Message )
                      {
                        Message oMessage1 = ( Message ) oObject1;
                        Message oMessage2 = ( Message ) oObject2;
                        
                        int iCategoryIndex1 = getCategoryIndex( oMessage1 );
                        int iCategoryIndex2 = getCategoryIndex( oMessage2 );
                        
                        if( iCategoryIndex1 == iCategoryIndex2 )
                        {
                          return oMessage1.getReceivedDate().compareTo( oMessage2.getReceivedDate() );
                        }
                        else
                        {
                          return iCategoryIndex1 - iCategoryIndex2;
                        }
                      }
                      else
                      {  //we have one String (category heading) and one HybridApp
                        Message oMessage = null;
                        String sString = null;
                        int iSwitch = 1;
                        if( oObject1 instanceof Message)
                        {
                          oMessage = ( Message ) oObject1;
                          sString = ( String ) oObject2;
                        }
                        else
                        {
                          oMessage = ( Message ) oObject2;
                          sString = ( String ) oObject1;
                          iSwitch = -1;
                        }
                        
                        int iMessageCategoryIndex = getCategoryIndex( oMessage );
                        int iCategoryIndex = getCategoryIndex( sString );
                        if( iCategoryIndex <= iMessageCategoryIndex )
                        {
                           return 1*iSwitch;
                        }
                        else
                        {
                          return -1*iSwitch;
                        }
                        
                      }
                      
                       return 0;
                    }
                    
                    private int getCategoryIndex( String sString )
                    {
                      for( int index = 0; index < m_asCategories.length; index++ )
                       {
                          if( m_asCategories[index].equalsIgnoreCase( sString ) )
                          {
                             return index;
                          }
                       }
                       return m_asCategories.length - 1;
                    }
                    
                    private int getCategoryIndex( Message oMessage )
                    {
                       MessageDb oMessageDb = (MessageDb) oMessage;
                       if( oMessageDb != null )
                       {
                         HybridApp oHybridApp = HybridAppDb.getHybridApp(oMessage.getModuleId(), oMessage.getModuleVersion());
                         String sModuleName = oHybridApp.getDisplayName();
                         if( sModuleName != null )
                         {
                            for( int index = 0; index < m_asCategories.length; index++ )
                            {
                              if( sModuleName.toLowerCase().indexOf( m_asCategories[index].toLowerCase() ) >= 0 )
                              {
                                return index;
                              }
                            }
                         }
                       }
                      return m_asCategories.length - 1;
                    }
                 });
              }
           }
    
  11. In the onResume method, make these changes (changes are shown in bold):
    try
             {
                // ANDROID_CUSTOMIZATION_POINT_FILTERING
               ArrayList<Message> alMessages = MessageDb.getMessages();
               ArrayList<Object> alMessagesObjects = new ArrayList( alMessages );
                this.m_adapter = new MessageAdapter( this, R.layout.workflowmessages, alMessagesObjects, UiHybridAppScreen.m_asHybridAppCategories );
                
                this.m_adapter.sort();
             }
    
  12. In the onListItemClick method, make these modifications (changes are shown in bold):
    public void onListItemClick(ListView  oParent, View  v, int iPos, long id )
           {
             try
             {
               Object oObject = m_adapter.getItem( iPos );
               if( oObject instanceof Message )
               {
                   Message oMsg = ( Message ) oObject;
    
                   // Check if workflow is available
                   HybridApp oHybridApp = HybridAppDb.getHybridApp( oMsg.getModuleId(), oMsg.getModuleVersion());
    
                   // CR668069 -Check if we can handle transform data - 1mb limit by sqllite database
                   try
                   {
                      oMsg.getTransformData();
                   }
                   catch ( Exception ex )
                   {
                      MocaLog.getAmpHostLog().logMessage( "Failed to read transform data", MocaLog.eMocaLogLevel.Normal );
       
                      new AlertDialog.Builder( this )
                      .setTitle( android.R.string.dialog_alert_title )
                      .setMessage( R.string.IDS_MSG_ERR_MESSAGE_TOO_LARGE )
                      .setIcon( android.R.drawable.ic_dialog_alert )
                      .setPositiveButton( android.R.string.ok,
                            new DialogInterface.OnClickListener()
                      {
                         public void onClick( DialogInterface dialog, int whichButton)
                         {
                            dialog.dismiss();
                         }
                      } )
                      .show();
    
                      return;
                   }
               
    
    
                   // Update read flag
                   if ( !oMsg.isMsgRead() )
                   {
                      m_adapter.notifyDataSetChanged();
                   }
    
                   // Open workflow
                   Intent oIntentHybridAppContainer =  new Intent( this, UiHybridAppContainer.class );
                   oIntentHybridAppContainer.putExtra( Consts.INTENT_PARAM_WORKFLOW_START_MODE, Consts.START_MODE_MESSAGE );
                   oIntentHybridAppContainer.putExtra( Consts.INTENT_PARAM_WORKFLOW_MSG_ID, oMsg.getMessageId() );
                   oIntentHybridAppContainer.putExtra( Consts.INTENT_PARAM_WORKFLOW_MODULE_ID, oMsg.getModuleId() );
                   oIntentHybridAppContainer.putExtra( Consts.INTENT_PARAM_WORKFLOW_MODULE_VERSION, oMsg.getModuleVersion() );
                   oIntentHybridAppContainer.putExtra( Consts.INTENT_PARAM_WORKFLOW_PROGRESS_TEXT, oMsg.getSubject() );
                   startActivityForResult( oIntentHybridAppContainer, Consts.INTENT_ID_WORKFLOW_CONTAINER );
               }
             }
             catch( Exception ex )
             {
                MocaLog.getAmpHostLog().logMessage( "Failed to open message. Caught exception - " + ex.getMessage(), MocaLog.eMocaLogLevel.Normal );
             }
           }
    
  13. Open the CustomizationHelper.java file, which is located in the ...\HybridWebContainer\src\com\sybase\hwc folder and edit the getHybridAppScreenClass() method, to change the class returned to your new class, which you created in step 2.
    That class must extend Activity.
  14. Update the manifest.xml file to include the new activity you create.