2018年7月31日 星期二

Writing a .csv file with non-latin characters

Try

write(0xFEFF)


Example

writer!!.write(0xFEFF)
writer!!.write(textWithSeparator.toString() + "\n")
writer!!.flush()

2018年5月29日 星期二

[Android] [Kotlin] Modify divider

Previously about the Expendable List View set in Navigation Drawer: 


If you don't like the divider line (separate line) too long, you wanna modify.
If you don't know how to fulfill what exactly you wanted, you can follow the steps as below:

1. Create xml file "list_divider.xml" - we can control the color and line style


Example:

list_divider.xml

<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:insetLeft="60dp"
    android:insetRight="5dp" >

    <shape android:shape="rectangle" >
        <solid android:color="#c0c0c0" />
        <size android:height="0.5dp" />
    </shape>

</inset>

android:insetLift & android:insetRight can control the line length.

 2. Use "android:divider" in your expandablelistview like :


<ExpandableListView
       .
       .
       .
       .
        android:divider:"@drawable/list_divider" // Call the "list_divider.xml" that you've created
</ExpandableListView>

You'll get the result as below:


Almost done!! We just modify the parent group list's divider line. We need to do one more thing!

3. Use "android:childDivider"

<ExpandableListView
       .
       .
       .
       .
        android:divider:"@drawable/list_divider"
        android:childDivider:"@drawable/list_divider" // add childDivider for child group list
</ExpandableListView>

Completed!



Hope you like my [Android] [Kotlin] share note.

Thanks for your attention & Have a nice day!!

2018年5月16日 星期三

[Android] [Kotlin] Only execute at the first time - use SharePreference

We can use SharePreference to save status as below :

fun saveIsFirstUsed() {
      val share = applicationContext().getSharedPreferences("GetSharedPreferences", Activity.MODE_PRIVATE)
      share.edit().putBoolean("isFirstUsed", false).apply()
}

fun getIsFirstUsed(): Boolean {
      val share = applicationContext().getSharedPreferences("GetSharedPreferences", Activity.MODE_PRIVATE)
      return share.getBoolean(SavePreference.SETTING_MAP_PANEL_STATUS, false)



// Judgement. If first use, go purposeActivity
if (MyApplication.getFirstUsed()) {
    val i = Intent(this@originalActivity, purposeActivity::clase.java)
    startActivity(i)
    finish()
} else {
    // Not first time, go purpose2Activity
    val i Intent(this@originalActivity, purpose2Activity::clase.jave)
    startActivity(i)
    finish()

[Android] [Kotlin] Set Expandable List View in Drawer Layout


If we want to create the layout as below, we need to create the Drawer and Expandable List View.

For fulfill our purpose, we need to create some files. 




First, your main_activity layout must add drawer and content expendable list.

activity_main.xml

<android.support.v4.widget.DrawerLayout 
xmlns:android="http://schemas.android.com/apk/res/android"    
xmlns:app="http://schemas.android.com/apk/res-auto"    
xmlns:tools="http://schemas.android.com/tools"    
android:id="@+id/drawerLayout"    
android:layout_width="match_parent"    
android:layout_height="match_parent"    
android:fitsSystemWindows="true">
    
    <android.support.design.widget.NavigationView
        android:id="@+id/naviView"        
        android:layout_width="wrap_content"        
        android:layout_height="match_parent"        
        android:layout_gravity="start"       
        app:headerLayout="@layout/drawer_header">

        <ExpandableListView         
           android:id="@+id/navigationmenu"            
           android:layout_width="wrap_content"            
           android:layout_height="match_parent"            
           android:layout_marginTop="151dp"            
           android:background="@android:color/white">        
        </ExpandableListView>

    </android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>

Add listheader.xml for each title in drawer.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout    
    xmlns:android="http://schemas.android.com/apk/res/android"    
    android:orientation="vertical"    
    android:layout_width="match_parent"    
    android:layout_height="match_parent">    
        <LinearLayout        
            android:layout_width="match_parent"        
            android:layout_height="match_parent"        
            android:layout_marginLeft="20dp"        
            android:orientation="horizontal">
        <ImageView        
            android:id="@+id/iconimage"            
            android:layout_width="30dp"            
            android:layout_height="30dp"            
            android:layout_gravity="center_vertical"            
            android:layout_marginStart="15dp"            
            android:layout_marginTop="10dp"            
            android:layout_marginBottom="10dp"/>
        <TextView            
            android:id="@+id/submenu"            
            android:layout_width="wrap_content"            
            android:layout_height="wrap_content"            
            android:layout_gravity="center_vertical"            
            android:layout_marginStart="15dp"            
            android:textColor="@color/grayColor_55"            
            android:textSize="16sp"/>
        <!-- Indicator right-->        
        <LinearLayout            
            android:layout_width="match_parent"            
            android:layout_height="match_parent"     
            android:layout_marginStart="140dp"     
            android:layout_gravity="end">
            
            <ImageView        
                android:id="@+id/indicatorImage"   
                android:layout_width="30dp"        
                android:layout_height="30dp"        
                android:layout_gravity="center_vertical"      
                android:layout_marginStart="10dp"/>
        </LinearLayout>
    </LinearLayout>
</android.support.constraint.ConstraintLayout>


Add list_submenu.xml for Child list.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"    
    android:orientation="vertical"    
    android:layout_width="match_parent"    
    android:layout_height="match_parent">
    <!--Expandable View, Children List-->
    <TextView   
        android:id="@+id/submenu"   
        android:layout_width="wrap_content"    
        android:layout_height="wrap_content"    
        android:layout_marginStart="50dp"     
        android:padding="10dp"   
        android:textColor="@color/grayColor_55" 
        android:textSize="16sp"/>
</LinearLayout>

Now we've already had the xml files that we need.

Prepare Kotlin files

1. We need a model for set icon and text title.

ExpandedMenuModel.kt

class ExpandedMenuModel {

    var iconName = ""    var iconImg = -1 // menu icon resource id}


2.  We need a Adapter

ExpandableListAdapter.kt

class ExpandableListAdapter(private val mContext: Context, private val mListDataHeader: ArrayList<ExpandedMenuModel> // header titles                            , // child data in format of header title, child title                            private val mListDataChild: HashMap<ExpandedMenuModel, ArrayList<String>>, internal var expandList: ExpandableListView) : BaseExpandableListAdapter() {

    override fun getGroupCount(): Int {
        val i = mListDataHeader.size        
        Log.d("GROUPCOUNT", i.toString())
        return this.mListDataHeader.size    }

    override fun getChildrenCount(groupPosition: Int): Int {
        var childCount = 0        
        if (groupPosition == 2 || groupPosition == 3) {
            childCount = this.mListDataChild[this.mListDataHeader[groupPosition]]!!.size        
        }
        return childCount
    }

    override fun getGroup(groupPosition: Int): Any {
        return this.mListDataHeader[groupPosition]
    }

    override fun getChild(groupPosition: Int, childPosition: Int): Any {
        Log.d("CHILD", mListDataChild[this.mListDataHeader[groupPosition]]!!.get(childPosition))
        return mListDataChild[this.mListDataHeader[groupPosition]]!!.get(childPosition)
    }

    override fun getGroupId(groupPosition: Int): Long {
        return groupPosition.toLong()
    }

    override fun getChildId(groupPosition: Int, childPosition: Int): Long {
        return childPosition.toLong()
    }

    override fun hasStableIds(): Boolean {
        return false    }

    override fun getGroupView(groupPosition: Int, isExpanded: Boolean, convertView: View?, parent: ViewGroup): View {
        var convertView = convertView
        val headerTitle = getGroup(groupPosition) as ExpandedMenuModel
        if (convertView == null) {
            val infalInflater = mContext                    
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
            convertView = infalInflater.inflate(R.layout.listheader, null)
        }
        val lblListHeader = convertView!!.findViewById(R.id.submenu) as TextView
        val headerIcon = convertView!!.findViewById(R.id.iconimage) as ImageView
        //  Expandable View, Indicator right        
        val headerIndicator = convertView.findViewById(R.id.indicatorImage) as ImageView
        lblListHeader.setTypeface(null, Typeface.NORMAL)
        lblListHeader.text = headerTitle.iconName        
        headerIcon.setImageResource(headerTitle.iconImg)
        // Expandable View, Indicator status        
        if (getChildrenCount( groupPosition ) == 0) {
            headerIndicator.visibility = View.GONE        
        } else {
            headerIndicator.visibility = View.VISIBLE            
            if (isExpanded) {
                headerIndicator.setBackgroundResource((R.drawable.ic_keyboard_arrow_up_black_18dp))
            } else {
                headerIndicator.setBackgroundResource((R.drawable.ic_keyboard_arrow_right_black_18dp))
            }
        }
        return convertView
    }

    override fun getChildView(groupPosition: Int, childPosition: Int, isLastChild: Boolean, convertView: View?, parent: ViewGroup): View {
        var convertView = convertView
        val childText = getChild(groupPosition, childPosition) as String

        if (convertView == null) {
            val infalInflater = this.mContext                    
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
            convertView = infalInflater.inflate(R.layout.list_submenu, null)
        }

        val txtListChild = convertView!!
                .findViewById(R.id.submenu) as TextView

        txtListChild.text = childText

        return convertView
    }

    override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean {
        return true    
    }
}


3. In MainActivity.kt , call your layout, add title and add onClickListener

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // ExpandableListView
    setNavigationView = findViewById<View>(R.id.naviView) as NavigationView

    setupDrawerContent(setNavigationView)

    // Add content in drawer
    prepareListData()

    mMenuAdapter = ExpandableListAdapter(this, listDataHeader, listDataChild, navigationmenu!!)
    navigationmenu!!.setAdapter(mMenuAdapter)
    //  Expandable View, hide original indicator    
    navigationmenu.setGroupIndicator(null)
    //*******************************************************************//

    // Set Listener, do anything you wanted
    // Group = Big Title, Child = SubTitle    
    navigationmenu.setOnGroupClickListener({ parent, _, groupPosition, _ ->        
    when (groupPosition) {
            // Position, first title = 0, second title = 1, .......
            0 -> {
                // Do anything you wanted
            }
            1 -> {
                // Do anything you wanted
} 2 -> { //Example - How to expand the drawer list if (parent.isGroupExpanded(groupPosition)) { parent.collapseGroup(groupPosition) } else { parent.expandGroup(groupPosition) parent.setOnChildClickListener({ parent, _, groupPosition, childPosition, _ -> when (childPosition) { 0 -> {
                                // Do anything you wanted
} 1 -> {
                                // Do anything you wanted
} }
                        // Collapse the expanded list
                        parent.collapseGroup(groupPosition)
                    })
                }
            }
            3 -> {
                if (parent.isGroupExpanded(groupPosition)) {
                    parent.collapseGroup(groupPosition)
                } else {
                    parent.expandGroup(groupPosition)
                    parent.setOnChildClickListener({ parent, _, groupPosition, childPosition, _ ->                        when (childPosition) {
                            0 -> {
                                // Do anything you wanted
} 1 -> {
                                // Do anything you wanted
} 2 -> {
                                // Do anything you wanted
} } parent.collapseGroup(groupPosition) }) } } 4 -> {
                // Do anything you wanted
} 5 -> {
                // Do anything you wanted
} } true }) }

private fun setupDrawerContent(navigationView: NavigationView?) {
    navigationView?.setNavigationItemSelectedListener { menuItem ->        
    selectDrawerItem(menuItem)
        true    
   }
}

//  ExpandableListView, Drawer content

// Add Anything you wanted

private fun prepareListData() {
    val drawerAddADDWII01 = ExpandedMenuModel()

    // First Part, group(Big Title)
    drawerAddADDWII01.iconName = getString(R.string.text_navi_add_device)
    drawerAddADDWII01.iconImg = R.drawable.ic_bluetooth_searching_black_24dp    
    // Adding data header    
    listDataHeader.add(drawerAddADDWII01)

    val drawerAccount02 = ExpandedMenuModel()
    drawerAccount02.iconName = getString(R.string.text_navi_accountManagement)
    drawerAccount02.iconImg = R.drawable.ic_account_box_black_24dp    listDataHeader.add(drawerAccount02)

    val drawerMap03 = ExpandedMenuModel()
    drawerMap03.iconName = getString(R.string.text_navi_title_map)
    drawerMap03.iconImg = R.drawable.ic_place_black_24dp    listDataHeader.add(drawerMap03)

    val drawerHelp04 = ExpandedMenuModel()
    drawerHelp04.iconName = getString(R.string.text_navi_title_help)
    drawerHelp04.iconImg = R.drawable.ic_help_black_24dp    listDataHeader.add(drawerHelp04)

    val drawerSetting05 = ExpandedMenuModel()
    drawerSetting05.iconName = getString(R.string.text_navi_setting)
    drawerSetting05.iconImg = R.drawable.ic_settings_black_24dp    listDataHeader.add(drawerSetting05)

    val drawerAbout06 = ExpandedMenuModel()
    drawerAbout06.iconName = getString(R.string.text_navi_about)
    drawerAbout06.iconImg = R.drawable.ic_phone_android_black_24dp    listDataHeader.add(drawerAbout06)

    // Second,  Adding child data (Subtitle)
    val childMap03 = ArrayList<String>()
    childMap03.add(getString(R.string.text_navi_personal))
    childMap03.add(getString(R.string.text_navi_air_map))

    val childHelp04 = ArrayList<String>()
    childHelp04.add(getString(R.string.text_navi_knowledge))
    childHelp04.add(getString(R.string.text_navi_q_and_a))
    childHelp04.add(getString(R.string.text_navi_tour))

    // This case, only 2 of Big title have sub title
    listDataChild[listDataHeader[2]] = childMap03
    listDataChild[listDataHeader[3]] = childHelp04
}


Thanks

[Android] [Kotlin] Add Button in Notification

First, make a notification in your NotificationActivity.kt

@RequiresApi(Build.VERSION_CODES.O)
private fun makeNotificationShow(DateType: Int, iconID: Bitmap, title: String, text: String?, dataValue: Int) {
    val bigStyle = NotificationCompat.BigTextStyle()
    bigStyle.bigText(text)
    val intent = Intent(m_context!!, MainActivity::class.java)
    // The stack builder object will contain an artificial back stack for the
    // started Activity.    
    // This ensures that navigating backward from the Activity leads out of    
    // your application to the Home screen.    
    val stackBuilder = TaskStackBuilder.create(m_context)
    // Adds the back stack for the Intent (but not the Intent itself)    
    stackBuilder.addParentStack(MainActivity::class.java)
    // Adds the Intent that starts the Activity to the top of the stack    
    stackBuilder.addNextIntent(intent)
    val intentAction = Intent(m_context!!, NotificationButtonReceiver::class.java)
    val intentAction2 = Intent(m_context!!, NotificationButtonReceiver::class.java)
    //This is optional if you have more than one buttons and want to differentiate between two
    intentAction.action = "action1"    
    val pi = PendingIntent.getBroadcast(m_context!!, DateType, intentAction,0 )
    intentAction2.action = "action2"    
    val pi2 = PendingIntent.getBroadcast(m_context!!, DateType, intentAction2, 0)
    val notification = NotificationCompat.Builder(m_context)
        .setSmallIcon(R.mipmap.ic_launcher)
        .setLargeIcon(iconID)
        .setContentTitle(title)
        .setStyle(NotificationCompat.BigTextStyle()
                .bigText(title))
        .setPriority(NotificationCompat.PRIORITY_MAX)
        .setCategory(NotificationCompat.CATEGORY_ALARM)
    // 0-no icon
        .addAction (0, m_context!!.getString(R.string.remindDismiss), pi)
        .addAction (0, m_context!!.getString(R.string.remindAfter_5_Mins), pi2)
        .setAutoCancel(true)
        .build()
    notification.contentIntent = pi
    
    // If Android > 7.0
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val notificationHelper = NotificationHelper(m_context!!)
    notificationHelper.set_TCOC_Value(dataValue)
    val action1 = Notification.Action(0, m_context!!.getString(R.string.remindDismiss), pi)
    val action2 = Notification.Action(0, m_context!!.getString(R.string.remindAfter_5_Mins), pi2)
    val NB = notificationHelper.getNotification1(title, text.toString())
            .addAction(action1)
            .addAction(action2)
            .setAutoCancel(true)
    notificationHelper.notify(DateType, NB)
}

Next, add NotificationButtonReceiver.kt

class NotificationButtonReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {

        val date = Date().time        
        when(intent.action)
        {
            "action1"->{
             performAction1(context,date)
            }
            "action2"->{
             performAction2(context,date)
            }

        }
        //This is used to close the notification tray        
        //   val it = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)        
        //   context.sendBroadcast(it)        
        val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        mNotificationManager.cancel(0x01)
        mNotificationManager.cancel(0x02)
    }

    fun performAction1(context: Context,nowTime:Long) {//設定明日再提醒        
        val share = context.getSharedPreferences("NotificationAction", Activity.MODE_PRIVATE)
        share.edit().putString("nextNotification", "tomorrow").apply()
        share.edit().putString("now time", nowTime.toString()).apply()
        Log.d("NotificationButton","action 1")
    }

    fun performAction2(context: Context,nowTime:Long) {//設定五分鐘提醒        
        val share = context.getSharedPreferences("NotificationAction", Activity.MODE_PRIVATE)
        share.edit().putString("nextNotification", "5min" ).apply()
        share.edit().putString("now time", nowTime.toString()).apply()
        Log.d("NotificationButton","action 2")
    }

}