Ayrıntılı Toast Kullanımı

Toast Mesajı Nedir?

Toast, Android uygulamalarda kullanıcılara uyarı veya bilgilendirme mesajları verilmesini sağlayan, bunun dışında uygulama test aşamasında işlemlerin gerçekleşip gerçekleşmediği hakkında bilgi edinmek amaçlı kullanılan mesaj türüdür.

Ayrıca, hata ayıklama amacıyla da kullanabilirsiniz. Bir tost, küçük bir açılır pencerede bir işlem hakkında basit geri bildirim sağlar.

Toast Message, Javascript’deki alert, Form Application’lardaki msgbox yada messagebox gibi anlayabiliriz. Ekrana veri yazdırmak için kullanılıyor.

Nasıl Kullanılır?

Toast mesajları tasarlanarak kullanılacağı gibi default yani varsayılan şekilde de gösterilebilir. Bunu basit anlamda aşağıdaki kod bloğunu sınıf içine yazarak kullanabiliriz.

makeText methoduna baktığımızda üç parametre aldığını göreceksiniz.

İlki uygulama içeriğini yani contexti , Hangi activity bu işleme erişecek bilgisi gibi bilgileri tutar.

ikincisi kullanıcıya gösterilecek kısa mesajı, parametre olarak String veri bekler.

üçüncüsü de Toast mesajının ekranda gösterilme süresini belirtiyor.

Toast Message süre olarak iki integer değer alabilir;

  • Uzun toast message süresi –> Toast.LENGTH_LONG
  • Kısa toast message süresi –>  Toast.LENGTH_SHORT

show (): Bu yöntem, Tost’u ekranda görüntülemek  için kullanılır. Bu yöntem, Toast’un makeText () yöntemini kullanarak oluşturduğumuz metni görüntüler.

Toast toast = Toast.makeText(getApplicationContext(), "Mesajımız..", Toast.LENGTH_LONG);
toast.show();

veya

Toast toast = Toast.makeText(getApplicationContext(), "Mesajımız..", Toast.LENGTH_LONG)show();

şeklinde gösterilir.

Toast nesnesi ise, android.widget paketi içerisinde sınıf olarak bulunur.

Toast.makeText(this, "Mesajımız..", Toast.LENGTH_SHORT).show();
Toast.makeText(getApplicationContext(),"Mesajımız..",Toast.LENGTH_LONG).show();

Yukarıdaki şekilde kullanıldığında mesaj, kısa süreli ekranda görünür. Ama eğer uzun süreli görünmesini istiyorsak Toast.LENGTH_SHORT kısmını Toast.LENGTH_LONG şeklinde değiştirebiliriz.

this yerine bazen getApplicationContext() olarak da görebilirsiniz, her ikiside çalışır.

Yapmış olduğumuz çalışma test amaçlı ve kodların işleyişini değinmek amaçlı, onCreate metodu içinde çalıştırdık.

Toast nesnenizin yerini belirleme

Ekranın alt kısmında, yatay olarak ortalanmış standart bir kısa mesaj bildirimi görünür. Bu konumu setGravity(int, int, int) yöntemini kullanarak değiştirebilirsiniz. Bu yöntem üç parametreyi kabul eder: Bir Gravity sabiti, bir x konumu ofseti ve bir y konumu ofseti.

Örneğin, durum mesajının sol üst köşede görünmesi gerektiğine karar verirseniz yerçekimi (gravity) değerini şu şekilde ayarlayabilirsiniz:

    toast.setGravity(Gravity.TOP|Gravity.LEFT, 0, 0); 

Toast toast = Toast.makeText(getApplicationContext(), "Mesajımız...", Toast.LENGTH_LONG);
toast.setGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL, 0, 0);
toast.show();

Toast mesajımızın yerini belirlemek için aşağıdaki konum sabitlerini kullanabilirsiniz.

  • TOP
  • BOTTOM
  • LEFT
  • RIGHT
  • CENTER
  • CENTER_HORIZONTAL
  • CENTER_VERTICAL

Aşağıdaki kod parçasını incelediğimizde ekran görüntüsünde de gördüğünüz gibi Toast mesajını en altta sola dayalı olarak konumlandırdık.

Toast toast = Toast.makeText(getApplicationContext(), "Mesajımız...", Toast.LENGTH_LONG);
toast.setGravity(Gravity.BOTTOM|Gravity.LEFT, 0, 0);
toast.show();

Toast mesajının kısa süre boyunca gözükmesi için :

Toast.makeText(getApplicationContext(), "Mesajımız…", Toast.LENGTH_SHORT).show();

Toast mesajının uzun süre boyunca gözükmesi için:

Toast.makeText(getApplicationContext(), "Mesajımız…", Toast.LENGTH_LONG).show();

Diyelim ki varsayılan şekilde kullanmak istemiyoruz. Toast mesajlarının daha güzel, kendimize ait bir tasarımla görünmesini istiyoruz. 

İlk önce uygulamanın açılış ekranındaki tasarımı yapalım.

toast_1.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/custom_toast_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:orientation="vertical">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@android:drawable/ic_delete" />
        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Toast YAZILI MESAJ"
            android:textColor="#FFF" />
</LinearLayout>

Java kodumuzda aşağıdadır. Yukarıda oluşturduğumuz görsel bileşeni, Toast mesajına setView yardımı ile verdik. Gördüğünüz gibi istediğimiz şekilde Toast mesajını oluşturmamız mümkün.

LayoutInflater inflater = getLayoutInflater();
                View layout = inflater.inflate(R.layout.toast_1,
                        (ViewGroup) findViewById(R.id.custom_toast_container));

                TextView text = layout.findViewById(R.id.text);
                text.setText("Bu bir Tost Mesajıdır ");
                Toast toast = new Toast(getApplicationContext());
                toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
                toast.setDuration(Toast.LENGTH_LONG);
                toast.setView(layout);
                toast.show();

Toast olarak sadece resim göstermek istersek

MainActivity.class

package com.ossmatematik.toastresimmesaji;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    Button Btn1,Btn2;

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

        Btn1= findViewById(R.id.button1);
        Btn2= findViewById(R.id.button2);

        Btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v)
            {
                Toast.makeText(getApplicationContext(),"Bu bir Tost MEsajıdır",Toast.LENGTH_LONG).show();
            }
        });

        Btn2.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v)
              {
                  ImageView resim=new ImageView(getApplicationContext());
                  resim.setImageResource(R.drawable.reklam);
                  Toast toast=new Toast(getApplicationContext());
                  toast.setView(resim);
                  toast.setDuration(Toast.LENGTH_LONG);
                  toast.show();
              }
        });



    }
}

Toast Mesajının bizim istediğimiz kadar kalmasını istersek

    public void sureliTOAST(String msg, int millisec) {
        Handler handler = null;
        final Toast[] toast_sureli = new Toast[1];
        for(int i = 0; i < millisec; i+=2000) {
            toast_sureli[0] = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
            toast_sureli[0].show();
            if(handler == null) {
                handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        toast_sureli[0].cancel();
                    }
                }, millisec);
            }
        }
    }

Bütün kodları toparlarsak;

axtivity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.nuri.toastresimmesaji.MainActivity">
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="NORMAL TOAST MESAJI"
        android:textSize="30sp" />
    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="RESİMLİ TOAST"
        android:textSize="30sp" />
    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="RESİM ve YAZILI TOAST"
        android:textSize="30sp" />
    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ZAMAN AYARLI TOAST(6 SANİYE)"
        android:textSize="30sp" />
</LinearLayout>

MainAcivity.java

package com.nuri.toastresimmesaji;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
    Button Btn1,Btn2,Btn3,Btn4;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Btn1= findViewById(R.id.button1);
        Btn2= findViewById(R.id.button2);
        Btn3= findViewById(R.id.button3);
        Btn4= findViewById(R.id.button4);

        Btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v)
            {
                Toast.makeText(getApplicationContext(),"Bu bir NORMAL Tost Mesajıdır",Toast.LENGTH_LONG).show();
            }
        });

        Btn2.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v)
              {
                  ImageView resim=new ImageView(getApplicationContext());
                  resim.setImageResource(R.drawable.reklam);
                  Toast toast=new Toast(getApplicationContext());
                  toast.setView(resim); //setView yani özel toast kullanımdan kaldırıldı. Bunun yerine SnackBar kullan
                  toast.setDuration(Toast.LENGTH_LONG);
                  toast.show();
              }
        });

        Btn3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v)
            {
                String Baslik = "DENEME";
                String mesajim = "Bu bir RESİMLİ Toast MESAJI";
                gosterTOAST(mesajim,Baslik);
            }
        });

        Btn4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v)
            {
                sureliTOAST("Bu bir Toast MESAJI",6000);
            }
        });
    }

    public void gosterTOAST(String Baslik, String msg)
    {
        LayoutInflater inflater = getLayoutInflater();
        View layout = inflater.inflate(R.layout.toast_ekrani,
                (ViewGroup) findViewById(R.id.relativeLayout1));
        TextView baslikText = layout.findViewById(R.id.toast_baslik);
        TextView textMesaj = layout.findViewById(R.id.toast_mesaj);
        baslikText.setText(Baslik);
        textMesaj.setText(msg);
        Toast toast = new Toast(getApplicationContext());
        toast.setGravity(Gravity.BOTTOM, 0, 0);
        toast.setDuration(Toast.LENGTH_LONG);
        toast.setView(layout);  //setView yani özel toast kullanımdan kaldırıldı. Bunun yerine SnackBar kullan
        toast.show();
    }

    public void sureliTOAST(String msg, int millisec) {
        Handler handler = null;
        final Toast[] toast_sureli = new Toast[1];
        for(int i = 0; i < millisec; i+=2000) {
            toast_sureli[0] = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
            toast_sureli[0].show();
            if(handler == null) {
                handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        toast_sureli[0].cancel();
                    }
                }, millisec);
            }
        }
    }
}

toast_ekrani.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/relativeLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:gravity="center_horizontal">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_orange_dark"
        android:orientation="vertical"
        android:padding="5dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            tools:ignore="UseCompoundDrawables">

            <ImageView
                android:id="@+id/imageView1"
                android:layout_width="120dp"
                android:layout_height="60dp"
                android:layout_below="@+id/textView1"
                android:layout_margin="5dip"
                android:src="@drawable/toast_onemli_uyari"
                tools:ignore="ContentDescription,InefficientWeight,ObsoleteLayoutParam" />

            <TextView
                android:id="@+id/toast_baslik"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:padding="10dp"
                android:text=""
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:textColor="@android:color/background_dark"
                android:textSize="18sp"
                tools:ignore="HardcodedText,InefficientWeight" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:padding="10dp">

            <TextView
                android:id="@+id/toast_mesaj"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/imageView1"
                android:layout_weight="1"
                android:gravity="center"
                android:hint="Mesaj"
                android:textColor="@color/colorPrimary"
                android:textSize="14sp"
                tools:ignore="HardcodedText,InefficientWeight,ObsoleteLayoutParam" />
        </LinearLayout>

    </LinearLayout>

</RelativeLayout>

Projenin tamamını

https://github.com/netmatematiknet/Toast

adresinden ücretsiz indirebilirsiniz.

Android .apk Dosyasından Kaynak Kodlara Erişim

Herhangi bir .apk dosyasından kaynak koduna erişebileceğinizi biliyor muydunuz? Marketten indirdiğiniz programların .apk uzantılı dosyalarında veya internetten indirdiğiniz .apk dosyalarında işlem yapabilirsiniz.

Evet yanlış okumadınız. Android uygulamalarınızı java ile yazıyorsanız .jar dosyaları gibi sıkıştırılmış dosyalar ile de muhakkak uğraşmışlığınız olmuştur. Her uygulama compile edildikten sonra class dosyaları yalın olarak bulunmaz ve tekrar farklı formatlara dönüştürülüp sıkıştırılmış dosya formatında sizlere .apk olarak servis edilir.

Peki android uygulamaların kodlarını görmek mümkün müdür ?

Kısmen evet, bu tür decompiler uygulamaları tamamen size kodu vermez. Bazı kısımlarını gösterir. Değişkenler, sabitler vs size farklı isimlerde gözükür, bazen çok anlamsız olduğunu düşünebilsek de ne arayacağınızı biliyorsanız, aradığınızı bulabilirsiniz.

Decompiler ne amaçlarla kullanılır ?

Bir uygulamanın kaynak kodlarına erişmek isteyebilirsiniz. Tabii, kimse size kendi yazdığı kaynak kodlarını paylaşmayacak olduğunu da düşünürseniz, ya uygulamayı çok iyi analiz edeceksiniz ki bu zaten gereklidir ya da kaynak dosyalardaki kullanım şekillerine bir yöntemle erişmeniz gerekecek. Bu tür bir uğraşı için, apk decompiler kullanabiliyorsunuz. Apk decompiler edilebilmesine karşılık olarak ise, uygulama güvenlik önlemleri sağlanabiliniyor.

Önce googleplay den ilgili apk nın adresini kopyalıyorsunuz.

Sonra bu uygulamanın apk dosyasını bilgisayara indirebilmek için

buraya tıkladığınızda çıkan ekrandaki satıra yazıyorsunuz. Ve bir süre sonra uygulamanın apk dosyası bilgisayarınıza indiriliyor.

1.Yol:

Online

Bu işlem için online araçlar hizmete sunulmuş durumda. Apk dosyasını bu sitelere yükleyerek kaynak kodları çok kısa sürede fazla uğraşmadan elde edebilirisiniz.

Çevrimiçi aracını kullanın, apk yükleyin ve kaynak kodunu alın.

http://www.javadecompilers.com/apk

http://www.decompileandroid.com

2.Yol:

Apktool Kullanımı

Apk dosyasını decompile ederek içerisindeki dosyaları okunabilir hale getiren bir araçtır. Buradan indirebilirsiniz.

Kullanımı:

d parametresi ile apk dosyasını decode ederek içerisindeki dosya ve klasörleri bir klasörde toplayabiliriz.

Apk uzantılı dosyamızın uzantısını .zip yapıp unzip ile açtığımızda da apk içerisindeki dosyalara erişebiliriz. Fakat o zaman AndroidManifest.xml dosyasının içerisini görüntüleyemiyoruz.

b parametresi ile dosyaları toplayarak apk dosyası haline getirebiliriz.

Bir .apk dosyasını açmaya çalıştığımızda karşımıza çıkan yapı şu şekildedir;

apktool

“.dex” formatında olan bu yapıyı anlamlandırılabilir hale getirmek için decompile etmeliyiz. Apktool android .apk dosyalarını decompile etmek için kullanılan araçtır. Decompile sonucunda smali adını verdiğimiz ara kodları elde ederiz.

.dex  <————–>   .smali   <—————–   java resource code

Apktool son versiyonunu https://ibotpeaches.github.io/Apktool/  adresinden indirebilirsiniz.

İndirmiş olduğunuz .jar dosyasını decompiler etmek için  “d”  parametresi ile çalıştırmalısınız.

decompiler

Decompiler sonucunda;

  • Resources (xml dosyaları ve resimler)
  • Manifest File
  • Yml dosyası (sdk ve versiyon bilgisi)
  • smali dosyası

oluşmaktadır.

Oluşan dosyalara ait bir ekran görüntüsü aşağıda veilmiştir.

apktool 1

Buradaki manifest dosyasını açtığımızda neredeyse orjinaliyle aynı bir manifest dosyası elde ettiğimizi görüyoruz.

manifest

Ayrıca Apktool sadece decompiler yapma işlemi için değil, aynı şekilde decompiler edilmiş bir apk dosyasını derleme yaparak paketleme işlemi için de  kullanılmaktadır.

Bunun için “b” (build) parametresi kullanılır.

derleme

3.Yol:

APK Easy Manager kullanımı

Hiç uğraşmadan komut vermeden  tek bir tuşa basarak apk dosyasını ayıklayabilir ve birleştirebilirsiniz decompiler kısmı apk ayıklama kısmıdır builder kısmı ise apk birleştirme kısmıdır.

APK Tool’ün yan kuruluşu da diyebileceğimiz bu proğram aynen APK Tool’ün yaptığı işlemlerin kısaltılmış hali olarak gözükmekte, bunda tek fark sadece arayüz eklenmiş, ilemler yine cmd ekranında yapıyor ama çalışılabilir exe arayüz olduğu için cmd ekranını göremiyoruz.

Uygulama çoğu apk’da işe yaradığı gibi bazılarındada işe yaramayabiliyor, çalışmak için apk yı üzerine sürüklemeniz yeterli

  • Öncelikle indirmek için tıklayınız -> APK Easy Manager
  • İndirdikten sonra açtığınızda aşağıdaki gibi bir program ile karşılaşacaksınız
apk easy manager

Nasıl kullanabilirsiniz ?

  • Bir .apk dosyasını bu program açık durumdayken, Drop APK Files here kısmına sürükleyiniz ve seçiniz.
  • Dosyanın ismi, uygulama içerisindeki listede seçili durumda iken, Decompiler kısmında Decompiler 1 – Ginderbread and below version Apps‘i seçiniz ve Start Decompiling butonuna tıklayınız.
  • İlgili apk dosyası decompile edildikten sonra, uygulamanın bulunduğu dizin içerisinde projects klasörü içerisinde uygulamaya ait yeni bir klasör açılmış ve erişebileceğiniz tüm kodlar burada bulunuyor olacaktır.
project

Buradada Project klasörüne girerek ayıkladığımız apk’yı düzenliyoruz türkçeleştireceksek türkçeleştirip bir sonraki aşamaya geçiyoruz

project 1

Bu bölümden türkçeleştireceksek values e giriyoruz resim degiştirmek vs için diğer klasörlere bakabilir ve düzenleyip degiştirebilirsiniz.

project 2

notepad++ ile açıyoruz

project 3

string kısımlarını türkçeleştirdikten sonra

project 4

kaydet diyip çıkıyoruz

project 5

daha sonra geri çıkarak klasörü builder bölümüne sürüklüyoruz ve builder 1 seçip start building butonuna basıyoruz.

project 6

oluşan dosya result klasörünün içerisinde belirecektir

project 7

Bu dosyayı alıp kullanabiliriz artık
Telefonunuza attığınız dosyanın yerini input butonuna basarak kayıt edilecegi yeri Output butonuna basarak seçiyoruz ve testkey seçenegini seçip sing the file butonuna basıyoruz ve dosyamız lisanslanmış oluyor böylece telefonunuza kurulabilir duruma gelmiş oldu.
Dosyaları yukarıda belirttiğim adreslerden indirerek uygulamaya başlayabilirsiniz.
Not : Her Apk dosyasında işe yaramayabiliyor

Uyğulamanın çalışması için sisteminizde java yüklü olmalıdır

Tüm bu aşamalardan sonra apk dosyanızı kullanabilir ve paylaşabilirsiniz umarım herkes için yararlı olur ve sizleri büyük sıkıntılardan kurtarır. Düzenlemelerinizi Notepad++ ile yapınız.

Java SE Development ve Runtime Kit 7u40

APK Easy Manager

Notepad++

4.Yol:

DEX2JAR KULLANIMI

Classes.dex dosyasını JAR dosyasına dönüştürmek için kullanılan bir araçtır. Buradan erişebilirsiniz.

Gerekli olan programlar:

DEX2JAR  Burdan dex2jar dosyasını indirin. ya da buradan .

Burdan jd-gui.exe dosyasını indirin ya da buradan .

Belirttiğim 2 programı indirdikten sonra kodlamasını görmek istediğiniz bir APK dosyası seçin ve sırasıyla işlemlere devam edin.

Yeni bir klasör oluşturun ve kodunu çözmek istediğiniz .apk dosyasına kopyalayın.

APK Dosyasını bilgisayarınıza indirin ve ornek.apk isimli dosyanızın sonuna “.zip” ekleyerek sıkıştırılmış hale dönüştürün.

Şimdi classes.dex dosyalarına vb. erişebilirsiniz. Bu aşamada çizilebilir dosyaları görebiliyor ancak xml ve Java dosyalarını göremiyorsunuz.

Zip haline dönüştürdüğünüz APK dosyasına sağ tıklayarak Dosyaları çıkart komutunu uygulayın.

İndirdiğiniz dex2jar dosyasını da “klasöre çıkar dex2jarx.x.x.x” diyin.

Çıkarttığınız “Ornek.Apk” klasörünün içindeki Classes.dex dosyasını üst satırda oluşturduğumuz “dex2jar” klasörünün içine atın.

Özetle apk yı zip haline çevirdik, sonra bunu klasör haline getirdik, sonra da bu klasör içindeki Classes.dex dosyasını dex2jar klasörünün içine kopyaladık.

Şimdi Başlat – Çalıştır – CMD komut dizinini açın.

“cd” komutu ile “dex2jar” klasörüne gidin ve klasör içine girdikten sonra şu komutu uygulayın:

yani komut satırına cd dex2jar yazıp entera basıyoruz

tabi bu işlemi dex2jar klasörünü nerede oluşturduysanız oraya gittikten sonra yapıyoruz.

dex2jar klasöründe iken komut satırına

dex2jar classes.dex” (Tırnaklar olmayacak)  yazıyoruz.

(mac terminali veya ubuntu için ./d2j-dex2jar.sh classes.dex yazın)

Bu komuttan sonra “classes_dex2jar.jar” diye bir dosya oluşacaktır.

dex2jar classes.dex yazınca
dex2jar’ is not recognized as an internal or external command,
operable program or batch file
hatasını alanlar bunu yazsın   d2j-dex2jar classes.dex
ayrıca java yazılımı pc nizde yüklü olması gerekli, yoksa hata alırsınız

Oluşturulan dosya dex2jar klasörünün içindedir

Classes_dex2jar.jar dosyasını ilk başta indirdiğimiz “Jd-Gui.exe” programı ile indirip Kodlara ulaşabilirsiniz.

şimdi sınıf dosyalarını görebiliyorsunuz

Bu sınıf dosyalarını kaydedin (jd-gui’de, Dosya -> Tüm Kaynakları Kaydet’e tıklayın) src ismine göre. Bu aşamada Java kaynağını elde edersiniz ancak .xml dosyaları hala okunamaz durumdadır, bu yüzden devam edin.

Şimdi başka bir yeni klasör aç

  1. apktool.bat (veya apktool / Linux için) ve apktool_<version>.jar // http://ibotpeaches.github.io/Apktool/install/
  2. jar dosyasını yukarıdan apktool.jar olarak yeniden adlandırın ve her iki dosyayı da aynı klasöre yerleştirin.
  3. bir dos kutusu (cmd.exe) açın ve bu klasöre geçin; Java Ortamı’nın kurulu olduğunu doğrulayın (Linux için ayrıca gerekli kütüphanelerle ilgili notları kontrol edin)
  4. google kullanarak framework-res.apk dosyasını indirin ve aynı klasöre koyun (Tüm apk dosyalarının framework-res.apk dosyasına ihtiyacı yoktur)
  5. Başlat: apktool decode [apk file] örneğin apktool decode compass.apk  gibiOrta sonuç : kaynak dosyaları, AndroidManifest.xml
  6. aPK dosyasını seçtiğiniz bir açıcı ile açınOrta sonuç classes.dex
  7. http://code.google.com/p/dex2jar/downloads/detail?name=dex2jar-0.0.9.15.Zip&can=2&q= adresinden dex2jar-0.0.9.15.Zip dosyasını indirip çıkarın
  8. classes.dex öğesini dex2jar.bat üzerine sürükleyip bırakın (veya bir DOS kutusuna <path_to>dex2jar.bat classes.dex yazın; Linux için dex2jar.sh kullanın)Orta sonuç classes_dex2jar.jar
  9. classes_dex2jar.jar_ paketini açın (kullanılan kod çözücüye bağlı olarak isteğe bağlı olabilir)
  10. sınıf dosyalarınızı kodabilirsiniz (örneğin JD-GUI veya DJ Decompiler ileSonuç : kaynak kodu
  1. Şimdi komutu apktool if framework-res.apk gibi çalıştırın (eğer burada yoksa get here yoksa) ve sonraki
  2. apktool d myApp.apk (burada myApp.apk, kodunu çözmek istediğiniz dosya adını belirtir)

şimdi bu klasörde bir dosya klasörü almak ve apk’ın xml dosyalarını kolayca okuyabilirsiniz.

Dex2Jar

Bir diğer tersine mühendislik aracı Dex2Jar  “.dex” formatında yer alan apk içerisindeki dosyaları  “.jar” uzantılı java binary dosyalarına çevirir.

.jar  uzantılı java binary dosyalarına dönüştürülmüş olan bu dosyalar başka bi java decompiler aracı kullanılarak rahatlıkla kaynak koda dönüştürülebilir.

Bu araç aşağıdaki linkten indirilebilir

https://sourceforge.net/projects/dex2jar/?source=type_redirect

ve programını açarak  “./d2j-dex2jar.sh”  aracılığıyla çalıştırabilirsiniz.

Yukarıda ekran görüntülerinde de görüldüğü gibi örnek olarak  “BGA_Mucahid.apk”  uygulaması decompiler edilerek  “output.jar”  dosyasına dönüştürülmüştür.

JD-GUI

Uygulamanın kaynak kodlarını görmeye yardımcı Java decompiler aracıdır. Classes.dex dosyasının dex2jar yardımıyla .jar dosyasına dönüştürülmesinden sonra jd-gui ile bu jar dosyasını açarak uygulamanın kaynak kodlarına erişebiliriz. Buradan indirebilirsiniz.

JD-GUI programı, dex2jar programı ile decompiler ettiğimiz  “.jar”  uzantılı java binary dosyalarını source koda çevirmemize yarayan bir decompiler aracıdır. Kullandığınız işletim sistemine göre uygun versiyonu;

http://java-decompiler.github.io/

adresinden indirebilirsiniz.

Bununla alakalı kısa bir örnek yapacak olursak adımlar şu şekildedir;

  • Öncelikle indirmiş olduğumuz  .jar  uzantılı JD-GUI programını  “java -jar jd-gui-1.4.0.jar”  komutuyla çalıştırıyoruz
  • Sonra grafik arayüze sahip olduğumuz programımızda “File” sekmesinden “Open File”  tuşuna basarak gelen dizin ekranından az önce “Dex2jar”  programı ile oluşturduğumuz  “output.jar” dosyasını seçiyoruz.
  • Bu işlemleri, oluşturulmuş olan “output.jar” dosyasını  JD-GUI  içerisine sürükle bırak yaparak da bu işlemleri kısa yoldan tanımlayabilirsiniz.
jd gui

Decompiler işlemi sonucunda ise android gelişiricinin yazmış olduğu kodları elde ediyoruz.

jd gui 1

APK Easy Tool (APK Tool GUI)

Apk Easy Tool, üzerinde çalıştığınız uygulamalar için APK dosyalarını yönetmenizi, decompile ederek içerisindeki dosyaları okunabilir hale getirmenizi, derlemenizi ve imzalamanızı sağlayan bir uygulamadır. Aslında bu araç daha önce de Mobil Uygulama Testlerinde Kullanılabilecek Araçlar yazımızda da bahsettiğim APKtool aracının arayüz aracılığıyla daha kolay bir kullanım sağlamasıdır.

İndirme Linkleri : 

Kullanımı :

  • Yukarıdaki indirme linkinden taşınabilir .zip dosyasını veya kurulum dosyasını indirebilirsiniz.
  • Kurulum için .msi dosyasını indirmeniz gerekecek fakat taşınabilir dosya da yalnızca .zip dosyasını açarak .exe dosyasını çalıştırmalısınız.
apkeasytool

Uygulama arayüzü açıldıktan sonra “Select APK” butonuna tıklayarak üzerinde çalışmak istediğiniz mobil uygulamanın .apk dosyasını seçin. Ayrıca bu işlemi yapmak yerine .apk dosyasını APK Easy Tool arayüzü üzerine sürükleyip bırakarak da yapabilirsiniz.

apkeasytool 1
  • Uygulama dosyası seçildikten sonra Decompile butonuna basarak  ayıklama işlemini yapabilirsiniz.
  • Burada “Decompile name” için paketi çıkarmak istediğiniz bir klasör ismi ve bu ayıkladığınız klasörle işiniz bittikten sonra derlemek istediğiniz de uygulama paketine vermek istediğiniz ismi “Compile name” alanını doldurmanız gerekecek.
  • Uygulamanın paket içerisindeki dosyaları ayıklandığı default olarak “Decompiled APKs” dizini içerisinde olacaktır. İsterseniz bu dizini değiştirerek klasörü başka bir yere çıkartabilirsiniz. Bunun için “change” butonuna basarak bilgisayarınızda herhangi bir dizin seçmeni yeterli olacaktır.
  • Decompiled edilen paket dosyaları tekrar derlenmek istendiğinde ise “Recompiled APKs” dizini içerisinde oluşturulacaktır. Aynı yöntemle dizini de değiştirebilirsiniz.
apkeasytool 2

Smali, Classes.dex dosyasının açılmış haline denir. Baksmali ise Classes.dex dosyasının düzenlenip tekrar kapanmış haline denir. Uygulamanın smali kodu üzerinden değişikler yapabilir ve programın işleyişine müdahale edebilirsiniz.

apkeasytool 3

Framework bölümü, Apk veya Jar  dosyasının android sürümüne uygun dosyaları oluşturmak için kullanılır. Rom uygulaması ise o roma ait, 3.parti bir uygulama ise Android sürümüne uygun herhangi bir romdan alınabilir. Framework dosyaları Rom dosyalarını açıp kapatmak içindir.

apkeasytool 4

Her bir işlem için ayrı bir dizin oluşturulacaktır.

apkeasytool 5

Herhangi bir hata ile karşılaşmanız durumunda ise Log Output bölümünde logları görüntüleyebilir veya uygulamanın klasör oluşturduğu noktaya gidebilirsiniz. Bu dosya için yine “BelgelerAPK Easy ToolLogs” dizinine bakabilirsiniz.

apkeasytool 6

Ayrıca derlediğiniz uygulamayı cihazınıza kolayca kurabilirsiniz. Cihazınız bilgisayara kablo ile bağlı durumda ve ayarlarınızda “USB Debugging” ve “Bilinmeyen Kaynaklar” bölümleri aktif durumda ise “Install APK” butonuna basarak uygulama paket dosyasını cihazınıza yüklemiş olacaksınız.

Android Uygulama İzinleri için Geniş bir Araştırma

İzin kelimesinin resmi anlamı, birisinin belirli bir şeyi yapmasına izin vermek anlamına gelir – herhangi bir işlem yapılması için verilen izin veya izindir. Android dünyasında, izinler mektup tanımını takip ediyor. Android uygulamaları, bazıları kullanıcılardan izin gerektiren bir dizi işlem gerçekleştirmek üzere oluşturulmuştur.

Bu yazı da Android’in izinlerini nasıl sınıflandırdığını ve kullanıcılardan nasıl izin alacağınızı anlamaya çalışacağız. Bu izinler doğru şekilde kullanılmazsa, uygulamanın çökmesine neden olabilir.

Varsayılan olarak, bir Android uygulaması kendisine verilen sıfır izinlerle başlar. Uygulamanın, cihazın korumalı özelliklerinden herhangi birini kullanması gerektiğinde (ağ istekleri gönderme, kameraya erişme, SMS gönderme vb.), kullanıcının bunu yapması için uygun izin alması gerekir.

Yani Android’in izin sistemi, kurulum sırasında bu izinlerin istenmesi nedeniyle baştan beri en büyük güvenlik sorunlarından biridir. Uygulama bir kez yüklendiğinde, herhangi bir kullanıcının izni ile tam olarak ne yaptığını kabul etmeden, herhangi bir kullanıcının onayı olmadan verilen tüm şeylere erişebiliyordu. Bu güvenlik zayıflığıyla kullanıcının kişisel verilerini toplamaya ve bunları kötü bir şekilde kullanmaya çalışan çok fazla yazılım mevcuttu. Android özgürlüktü ama bu sebepten de çok eleştiriliyordu.

Özgürlüktü ama dezavantajı da oldukça açıktı: geliştiriciler veri toplamak için izin almaya ve kullanıcının gizliliğini ihlal etmeye başladı. Google, uygulamanın söz konusu izinleri gerçekten gerektirip gerektirmediğini kontrol etmediğinden ve kullanıcının belirli izinleri sağlama ve uygulamayı kullanmaya devam etme seçeneği bulunmadığından, geliştiriciler sistem bilgisine veya mikrofona herhangi bir kısıtlama olmadan erişme konusunda çok rahattılar

izin 1.

Android içerisinde 130’dan fazla farklı izin türü vardır. Geliştiricilerin bunlardan her biri için izin alması zordu.  Daha da kötüsü, uygulamanızın kullanıcıların kaç tane iznine ihtiyacı olduğunu görmelerinin korkutuculuğundan ziyade  neden bu kadar çok izne ihtiyacınız olduğunu kullanıcıya açıklamak çok daha zordur.

   Android M (Marshmallow , Android 6.0, API 23)

İOS’un aksine, Android uygulama izinlerine partiye biraz geç geldi. Android Marshmallow (Android M), 5 Ekim 2015 tarihinde piyasaya sürüldü.

Marshmallow’dan önce, izinler kurulum zamanında ele alınmış AndroidManifest.xml ve proje içerisinde belirtilmiştir . İzinlerin tam listesi burada bulunabilir.

Marshmallow’dan önce izinler çok daha basittir (API 23). Tüm izinler kurulum sırasında ele alındı. Bir kullanıcı Google Play Store’dan bir uygulama yüklemeye gittiğinde , kullanıcıya uygulamanın gerekli kıldığı izinlerin bir listesi sunuldu (bazı kişiler buna “izin duvarı” olarak adlandırılıyordu. Kullanıcı tüm izinleri kabul edip devam edebilirdi. Uygulamayı yüklemek veya uygulamayı yüklememeye karar vermekle, kullanıcı izinlerin tamamına izin veriyordu ya da hiç birine izin vermiyordu.Uygulama için yalnızca belirli izinler vermenin bir yolu yoktu ve kullanıcının uygulama yüklendikten sonra belirli izinleri iptal etmesinin bir yolu yoktu.

Android Marshmallow’un halka açık sürümüyle Google, Android için çalışma zamanı izinlerini sundu ve böylece izinler alanını daha iyi hale getirdi. Android Marshmallow, yalnızca izinleri basitleştirmek değil, aynı zamanda gereken izin sayısını azaltmak için uygulama izinlerinde tamamen yeni bir uygulama sunar.

Peki daha önce başlatılmış olan uygulamaya ne oldu?

Eski uygulamalar Android Marshmallow’da çalışacak mı? TargetSdkVersion 22 ya da daha az ise cevap evet .

Bu yeni izin sistemi şu anda size biraz panik getirebilir. “Hey! 3 yıl önce başlattığım uygulamama ne oldu. Android 6.0 aygıtına yüklenmişse, bu davranış da geçerli mi? Uygulamam da çökecek mi?!?”

Endişelenme. Android ekibi çoktan düşünmüş. Uygulamanın targetSdkVersion değeri 23’ten küçükse, uygulamanın henüz yeni izin sistemiyle test edilmediği ve aynı eski davranışa geçeceği varsayılır: kullanıcı yükleme zamanında her bir izni kabul etmek zorundadır ve hepsine izin verilir kurulduktan sonra!

Sonuç olarak, uygulama önceki gibi mükemmel şekilde çalışacaktır. Yine de, kullanıcının bundan sonra hala bir izni iptal edebileceğini unutmayın!  Her ne kadar Android 6.0 bunu yapmaya çalıştıklarında kullanıcıyı uyarıyorlar ancak yine de iptal edebiliyorlar.

mpermission 22denyperm

Şu an kafandaki bir sonraki soru. Peki başvurum çökecek mi?

Android ekibi aracılığıyla Tanrı’dan gönderilen böylesi bir nezaket. TargetSdkVersion uygulamasının 23’ten daha az olduğu uygulamada izinli kullanıcının iptal edilmesini gerektiren bir işlev çağırdığımızda, İstisna atılmaz. Bunun yerine sadece hiçbir şey yapmaz. Değeri döndüren işlev için null döndürür veya 0 duruma göre  değişir.

target sdk version2223

   Android 6.0 Marshmallow’da, uygulama kurulum sırasında herhangi bir izin verilmez. Bunun yerine, uygulama çalışma zamanında kullanıcıdan birer birer izin istemelidir.

runtime permission

Sağdaki reismde yani Api 23 den sonra geliştiricinin, kullanıcının henüz izin vermemiş olması gereken izni gerektiren bazı işlevleri çağırmayı denemesi durumunda, işlev aniden uygulamanın çökmesine neden olacak bir İstisna atar.

runtime permissioncrash

Ayrıca, kullanıcı telefonun Ayarlar uygulamasını kullanarak verilen izni istediği zaman iptal edebilir.

permission srevoke

Şimdi geliştirici artık uygulama kurulumunda tüm izinlere sahip değil. Bunun yerine, geliştiricinin bir resmi tıklatmak veya bir dosyayı kaydetmek için kullanıcının deposuna erişmek için kamerayı kullanmak gibi belirli bir işlemi gerçekleştirme iznini istemesi gerekir. Google ayrıca Android’deki izinler kümesini normal ve tehlikeli izinlere ayırdı .

Normal ve tehlikeli izinlerin tam listesi Android Dokümantasyonunda bulunmaktadır .

Android M Permissions

Normal İzinler

Kurulum sırasında otomatik olarak verilecek ve iptal edilemeyecek bazı izinler vardır. Buna Normal İzin (PROTECTION_NORMAL) diyoruz.

Normal izinler, kullanıcının gizliliği veya cihazın çalışması için risk teşkil etmeyen izinlerdir. Sistem bu izinleri otomatik olarak verir. Bunlar arasında internete bağlanmak, ağ, Bluetooth, wifi ve NFC bilgilerini almak, alarmları ve duvar kağıtlarını ayarlamak ve bir cihazdaki ses ayarlarını değiştirmek sayılabilir.

Normal izinler, uygulamanızın uygulama sanal alanı dışındaki verilere veya kaynaklara erişmesi gereken alanları kapsar, ancak kullanıcının gizliliği veya diğer uygulamaların çalışması için çok az risk olduğu yerlerdir. Örneğin, saat dilimini ayarlama izni normal bir izindir.

Bir uygulama normal bir izne ihtiyaç duyduğunu beyan ederse, sistem otomatik olarak bu izni yükleme sırasında uygulamayı verir. Sistem, kullanıcıdan normal izinler vermesini istemez ve kullanıcılar bu izinleri iptal edemez.

Android 9’dan itibaren (API seviyesi 28), aşağıdaki izinler şöyle sınıflandırılır PROTECTION_NORMAL:

İşte bunların tam listesi:

android.permission.ACCESS_LOCATION_EXTRA_COMMANDS 
android.permission.ACCESS_NETWORK_STATE 
android.permission.ACCESS_NOTIFICATION_POLICY 
android.permission.ACCESS_WIFI_STATE 
android.permission.ACCESS_WIMAX_STATE 
android.permission.BLUETOOTH 
android.permission.BLUETOOTH_ADMIN 
android.permission.BROADCAST_STICKY 
android.permission.CHANGE_NETWORK_STATE 
android.permission.CHANGE_WIFI_MULTICAST_STATE 
android.permission.CHANGE_WIFI_STATE 
android.permission.CHANGE_WIMAX_STATE 
android.permission.DISABLE_KEYGUARD 
android.permission.EXPAND_STATUS_BAR 
android.permission.FLASHLIGHT 
android.permission.GET_ACCOUNTS Instagram Hesabındaki Resim ve Videoları android.permission.FLASHLIGHT android.permission.GET_ACCOUNTS
android.permission.FLASHLIGHT
android.permission.INTERNET 
android.permission.KILL_BACKGROUND_PROCESSES 
android.permission.MODIFY_AUDIO_SETTINGS 
android.permission.NFC 
android.permission.READ_SYNC_SETTINGS 
android.permission.READ_SYNC_STATS 
android.permission.RECEIVE_BOOT_COMPLETED 
android.permission.REORDER_TASKS 
android.permission.REQUEST_INSTALL_PACKAGES 
android.permission.SET_TIME_ZONE 
android.permission.SET_WALLPAPER 
android.permission.SET_WALLPAPER_HINTS 
android.permission.SUBSCRIBED_FEEDS_READ 
android.permission.TRANSMIT_IR 
android.permission.USE_FINGERPRINT 
android.permission.VIBRATE 
android.permission.WAKE_LOCK 
android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM 
com.android.launcher.permission.INSTALL_SHORTCUT 
com.android.launcher.permission.UNINSTALL_SHORTCUT

Sadece basitçe bu izin isteklerini  AndroidManifest.xml dosyasına yazın, gayet iyi sonuç verecektir. Bu izinler kullanıcı tarafından İptal edilemediğinden  yazılım içerisinde bu listelenen izinleri kontrol etmeniz gerekmez.

Normal izinlerin TAM  listesi

 

İmza İzinleri

Sistem bu uygulama izinlerini yükleme sırasında verir, ancak yalnızca izin kullanmaya çalışan uygulama, izni tanımlayan uygulama ile aynı sertifika ile imzalandığında verilir.

Android 8.1’den itibaren (API seviyesi 27), üçüncü taraf uygulamaların kullanabileceği aşağıdaki izinler şöyle sınıflandırılır PROTECTION_SIGNATURE:

 

Tehlikeli izinler

   Tehlikeli izinler, uygulamanın, kullanıcının kişisel bilgilerini içeren veri veya kaynakları istediği veya kullanıcının depolanan verilerini veya diğer uygulamaların çalışmasını etkileyebileceği alanları kapsar. kullanıcının gizliliğini veya cihazın çalışmasını potansiyel olarak etkileyebilecek izinlerdir. Kullanıcı açıkça bu izinleri vermeyi kabul etmelidir. Bunlar, kameraya, rehbere, konuma, mikrofona, sensörlere, SMS’e ve depolamaya erişmeyi içerir.

   Örneğin, kullanıcının bağlantılarını okuyabilmek tehlikeli bir izindir. Bir uygulama tehlikeli bir izin gerektirdiğini bildirirse, kullanıcının açıkça uygulamaya izin vermesi gerekir. Kullanıcı izni onaylayana kadar, uygulamanız bu izne bağlı işlevler sağlayamaz.

Tehlikeli izinlerin TAM  listesi

Özel İzinler

Normal ve tehlikeli izinler gibi davranmayan birkaç izin vardır. SYSTEM_ALERT_WINDOWve WRITE_SETTINGSözellikle hassastır, bu nedenle çoğu uygulama bunları kullanmamalı. Bir uygulama şu izinlere birini gerekiyorsa, apaçık izne beyan, gerekir ve kullanıcının izni talep eden bir niyet gönderin. Sistem, kullanıcıya ayrıntılı bir yönetim ekranı göstererek amacına cevap verir.

Bu izinlerin nasıl isteneceği ile ilgili detaylar için bakınız SYSTEM_ALERT_WINDOWve WRITE_SETTINGSreferans girişleri.

Android sistemi tarafından sağlanan tüm izinler adresinde bulunabilir Manifest.permission

İzin Grupları

İzinler, bir cihazın yetenekleri veya özellikleriyle ilgili gruplar halinde düzenlenir. Bu sistem altında, izin talepleri grup düzeyinde ele alınmakta ve tek bir izin grubu, uygulama bildiriminde birkaç izin beyanına karşılık gelmektedir. Örneğin, SMS grubu hem bildirimleri hem READ_SMSde RECEIVE_SMSbildirimleri içerir. Bu şekilde gruplama izinleri, kullanıcının karmaşık ve teknik izin talepleri tarafından boğulmadan daha anlamlı ve bilinçli seçimler yapmasını sağlar.

Tehlikeli izinler kendi içerisinde gruplara ayrılmıştır. İzinler, dokuz gruba ayrılarak kullanıcıların bir grup halinde bir araya getirilerek tek bir işlemle kapsanan tüm izinleri vermelerini sağlar.

Örneğin, Bu, kullanıcının konumunu bulmak için GPS’i kullanmanız gerekirse, ACCESS_FINE_LOCATION ve ACCESS_COARSE_LOCATION gibi 2 adet izin belirtmeniz anlamına geliyordu ya da  bir kullanıcıya Rehber’i görüntüleme, düzenleme ve ekleme izni vermek için 3 adet izin belirtmek gerekiyordu.

Bunun yerine izinleri tek tek almak yerine izin grubuna (Kişiler adı verilen) izin istemek daha etkilidir.

   İzin Grupları Konum, Rehber, Telefon, Sensörler, SMS ve Depolama gibi benzer işlemleri gerçekleştiren izinleri basitleştirmeye çalışır. Bir uygulama grubu şu anda tek bir izin grubuna bir ila yedi izin arasında herhangi bir yerde bir araya geliyor. Bu, bir gruptaki tüm izinlerin tek seferde talep edebileceğiniz anlamına gelir!

Tüm tehlikeli Android izinleri izin gruplarına aittir. Herhangi bir izin, koruma seviyesinden bağımsız olarak bir izin grubuna ait olabilir. Bununla birlikte, bir izin grubu yalnızca izin tehlikeli olduğunda kullanıcı deneyimini etkiler.

Cihaz Android 6.0 kullanıyorsa (API seviye 23) ve uygulamanın targetSdkVersion23 veya daha üstü ise, uygulamanız tehlikeli bir izin istediğinde aşağıdaki sistem davranışı uygulanır:

  • Uygulamanın izin grubunda şu anda herhangi bir izni yoksa, sistem, uygulamanın erişmek istediği izin grubunu tanımlayan kullanıcıya izin isteği iletişim kutusunu gösterir. İletişim kutusu, o gruptaki belirli izni açıklamıyor. Örneğin, bir uygulama READ_CONTACTSizin isterse, sistem iletişim kutusu sadece uygulamanın cihazın bağlantılarına erişmesi gerektiğini söyler. Kullanıcı onay verirse, sistem uygulamaya sadece istediği izni verir.
  • Uygulamaya, aynı izin grubunda başka bir tehlikeli izin verilmişse, sistem kullanıcı ile herhangi bir etkileşime girmeden derhal izni verir. Örneğin, bir uygulamanın daha önce talep etmesi ve READ_CONTACTSizin verilmiş olması ve daha sonra talep WRITE_CONTACTSetmesi durumunda, sistem, izinler iletişim kutusunu kullanıcıya göstermeden hemen bu izni verir.

Cihaz Android 5.1 kullanıyorsa (API seviye 22) veya daha düşükse veya uygulama targetSdkVersion22 veya daha düşükse, sistem kullanıcıdan yükleme sırasında izinleri vermesini ister. Bir kez daha, sistem kullanıcıya bireysel izinleri değil, uygulamanın hangi izin grubunu gerektirdiğini söyler . Örneğin, bir uygulama READ_CONTACTSkurulum istediğinde , iletişim kutusu Rehber grubunu listeler. Kullanıcı kabul ettiğinde, uygulamaya yalnızca READ_CONTACTSizin verilir.

   Not: Kullanıcı, aynı grupta başka bir izin vermiş olsa bile, uygulamanızın ihtiyacı olan her izni açıkça talep etmesi gerekir. Ek olarak, izinlerin gruplara ayrılması gelecekteki Android sürümlerinde değişebilir. Kodunuz, aynı grupta bulunan belirli bir izin grubuna bağlı bir mantığa sahip olmamalıdır.

Tehlikeli izinler ve izin grupları.

İzin GrubuİzinlerAçıklamaAçıklama
CALENDAR(Takvim) Kullanıcının takvimi ile ilgili çalışma zamanı izinleri için kullanılır.

 

Manifest.permission.READ_CALENDAR (Takvim Etkinlikleri OKU)

Manifest.permission.WRITE_CALENDAR (Takvim Etkinlikleri YAZ)

android.permission-group.CALENDAR
CALL_LOG (Çağrı Geçmişi) İlişkili telefon özellikleri ile ilgili izinler için kullanılır.android.permission-group.CALL_LOG
CAMERA (Kamera) Kameraya erişmek veya cihazdan fotoğraf / video çekmekle ilgili izinler için kullanılır.

 

Manifest.permission.CAMERA (Kameraya Erişim)

android.permission-group.CAMERA
CONTACTS(İletişim) Bu cihazdaki kişiler ve profillerle ilgili çalışma zamanı izinleri için kullanılır.

 

Manifest.permission.READ_CONTACTS (Telefon Rehberini OKU)

Manifest.permission.WRITE_CONTACTS (Telefon Rehberine YAZ)

android.permission-group.CONTACTS
LOCATION (Yer) Cihaz konumuna erişime izin veren izinler için kullanılır.

 

Manifest.permission.ACCESS_FINE_LOCATION (Kesin Konum)

Manifest.permission.ACCESS_COARSE_LOCATION (Genel Konum)

android.permission-group.LOCATION
MICROPHONE(Mikrofon) Aygıttan mikrofon sesine erişimle ilgili izinler için kullanılır. Telefon görüşmelerinin de ses yakaladığını ancak ayrı (daha görünür) bir izin grubunda olduğunu unutmayın.

 

Manifest.permission.RECORD_AUDIO (Mikrofon ile kayıt)

android.permission-group.MICROPHONE
PHONE(Telefon İlişkili telefon özellikleri ile ilgili izinler için kullanılır.

 

Manifest.permission.CALL_PHONE (Telefonla Arama)

android.permission-group.PHONE
SENSORS(Vücut Sensörleri) Gövde veya çevresel sensörlere erişim ile ilgili izinler için kullanılır.android.permission-group.SENSORS
SMS(SMS) Kullanıcının SMS mesajlarıyla ilgili çalışma zamanı izinleri için kullanılır.android.permission-group.SMS
STORAGE(Depolama) Paylaşılan harici depolama alanıyla ilgili çalışma zamanı izinleri için kullanılır.

 

Manifest.permission.READ_EXTERNAL_STORAGE (Sd veya Harici Diski OKU)

Manifest.permission.WRITE_EXTERNAL_STORAGE (Sd veya Harici Diske YAZ)

android.permission-group.STORAGE


Tehlikeli izinlerin TAM  listesi

Uygulama için İzin Alma

Artık uygulamamızın yeni Çalışma Zamanı İznini mükemmel bir şekilde desteklemesinin zamanı geldi. Önce compileSdkVersion ve  targetSdkVersion ayarlarını 23 yaparak başlayalım.

android {
    compileSdkVersion 23
    ...

    defaultConfig {
        ...
        targetSdkVersion 23
        ...
    }

Sonraki adım, AndroidManifest.xml aynı eski yöntemle izin vermek

<uses-permission android:name="android.permission.WRITE_CONTACTS"/>

Dikkat: Manfest izni verilmezse uygulama kilitlenir.

İzinler, aşağıdaki tablo gibi İzin Grubunda gruplandırılmıştır .

permgroup

Bir uygulamada tehlikeli kategorisindeki bir izne ihtiyaç varsa, bu izin kullanıcı tarafından daha önce onaylanmış bile olsa her seferinde uygulama tarafından kontrol edilmelidir. Çünkü kullanıcı verdiği izinden istediği an cayma hakkına sahiptir. Telefonun “Ayarlar – Uygulamalar – İlgili Uygulama – İzinler” kısmından bu işlemi yapabilir.

Android uygulamamız tehlikeli kategorisindeki bir izne ihtiyaç duyarsa, bu yetki için mutlaka kullanıcıya sorulması gerekir. Bir sonraki adım, izin verilip verilmediğini kontrol etmek için bir işlev oluşturmaktır.

//Öyleyse önce kullanıcıdan izin istemek için bir iletişim kutusu çağıralım. Sonra yeni bir kişi oluşturarak bir sonraki adıma geçebiliriz.

Not: Bir izin grubunda herhangi bir izin verilirse aynı gruptaki başka bir izin de otomatik olarak verilecektir.

Yani, bir kez WRITE_CONTACTS izni verildiyse READ_CONTACTS ve GET_ACCOUNTS izinleri de otomatik olarak verilir.

(READ_CONTACTS ,   WRITE_CONTACTS ve GET_ACCOUNTS  aynı grupta olduğu için.) (ama AndroidManifest.xml dosyasında izin istemek zorundayız)

 1. Önce iznin verilip verilmediğini kontrol edelim

checkSelfPermission(Context context, String permission

Uygulama tarafından izin kontrolü ContextCompat.checkSelfPermission(Context context, String permission) metodu ile yapılır.

Bu metotta kullanıcı

izin verdiğinde PackageManager.PERMISSION_GRANTED döndürülürken,

izin vermediğinde ise PackageManager.PERMISSION_DENIED döndürülür.

    private void izin_Kontrolet_Al() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
            //Önceden izin VERİLMİŞ öyleyse Serbestçe istediğimizi yapalım.
            yapilacaklar();
        } else {
            // Önceden izin verilmemiş öyleyse İZİN İSTEYELİM
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, ONAY_KODU);
        }
        return;
    }

2. İzin önceden alınmadıysa izin isteyelim

requestPermissions(String [] izinler, int ONAY_KODU)

İzin alma işlemi için android sistemine ait standart bir dialog mevcuttur. Bu dialog requestPermissions() metodu ile çağrılır ve özelleştirilemez.

Activity izni almak için (Üstteki kodlara ekleme yapalım)

Daha önceden izin verilmişse, çalıştırılacak kodlar çağrılıyor, bu örnekte  yapilacaklar()  çağrılıyor.

İzin verilmediyse requestPermissions(context, new String [] {izinler}, int ONAY_KODU)  ile izin istemek için aşağıdaki gibi bir iletişim kutusunu  çağırılıyor.

final private int ONAY_KODU = 1234;
    private void izin_Kontrolet_Al() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
            //Önceden izin VERİLMİŞ öyleyse Serbestçe istediğimizi yapalım.
            yapilacaklar();
        } else {
            // Önceden izin verilmemiş öyleyse İZİN İSTEYELİM
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, ONAY_KODU);
        }
        return;
    }
requestpermission
permissions anatomy
  1. İzin grubu simgesi
  2. Uygulama ismi
  3. “Bir daha asla sorma” onay kutusu (Bir kullanıcı iki kez izin vermezse bu görüntülenir)
  4. Çoklu diyaloglar için gösterge
  5. Aksiyon

3. İzin verilip verilmediğini kontrol edelim

İzin istedik ama izin verildi mi acaba? İşlem sonucunda izin verilip verilmediğini kontrol etmek için ise

onRequestPermissionsResult (int permsRequestCode, String [] izinleri, int [] grantResults

komutları kullanılır.

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        //public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case ONAY_KODU: {
                // CALL_PHONE izni verilip verilmediğini kontrol edin
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(Eeeeeee.this, "CALL_PHONE izni VERİLDİ", Toast.LENGTH_SHORT).show();
                    yapilacaklar();
                } else {
                    Toast.makeText(Eeeeeee.this, "CALL_PHONE izni REDDEDİLDİ", Toast.LENGTH_SHORT).show();
                }
                return;
            }
                default:
                    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

   Yukarıdaki kodda, istek kodunun izin talep ederken tarafımızdan gönderilen istek koduyla eşleşip eşleşmediğini kontrol ediyoruz. İstek kodu eşleşirse, kullanıcının izin verdiği veya reddedildiği izinleri kontrol ediyoruz. Kullanıcı izin verirse, CALL_PHONE başlatabiliriz, aksi takdirde kullanıcının izin vermesine izin verecek bir mesaj gösterebiliriz.

4. izin almadan önce neden izin istediğimizi izah edelim

Eğer kullanıcı izin için ilk kez çıkan dialog’a izin vermeyip, yeniden o özelliği kullanmaya çalışırsa, büyük ihtimalle o iznin ne için gerekli olduğunu anlamamıştır. Bu sebeple kullanıcıya standart izin dialog’u gösterilmeden önce, uygulamanın izne neden ihtiyacı olduğunu anlatan bir açıklama gösterilmelidir. Eğer kullanıcı açıklamaya ikna olup izin vermeyi kabul ederse, standart izin penceresine yeniden yönlendirilir.

Android sistemi, kullanıcıya bir açıklama göstermenin gerekli olup olmadığına karar vermemizi kolaylaştıran bir metod  sunmuştur:

shouldShowRequestPermissionRationale() metodu

true dönerse, kullanıcıya daha önceden android standart dialog’u gösterilmiş ve kullanıcı izni onaylamamıştır. Bu sebeple true döndüğü durumlarda önce iznin ne için gerekli olduğunu anlatan bir açıklama gösterilmesi ve kullanıcı bu açıklamayı onaylarsa standart izin dialog’una yönlendirilmesi gerekir.

İzin kullanıcıdan ilk defa istenecekse ya da kullanıcı “Never ask again” durumu onaylanmışsa metod false döner.

requestPermissions  çağrılmadan önce biz izni neden talep ettiğimizi  shouldShowRequestPermissionRationale metodu ile kullanıcıya bir pencerede  gerekçe göstermemiz gerekir.

ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CALL_LOG)

    private void izin_Kontrolet_Al() {
        int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.CALL_PHONE);
        if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
            if (!shouldShowRequestPermissionRationale(Manifest.permission.CALL_PHONE)) {
                showMessageOKCancel("Çağrı için izin vermeniz gerekir", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                requestPermissions(new String[] {Manifest.permission.CALL_PHONE}, ONAY_KODU);
                            }
                        });
                return;
            }
            requestPermissions(new String[] {Manifest.permission.CALL_PHONE}, ONAY_KODU);
            return;
        }
        yapilacaklar();
    }
    private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(Eeeeeee.this)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", null)
                .create()
                .show();
    }

Birinci durumda açılan diyalog kutusunda neden izin istediğimizi açıklıyoruz.

İzine hayır derse pencere kapanıyor dolayısıyla “bir daha sorma” kutusunun işaretlenmesine engel olmuş oluyoruz. Uygulama tekrar açıldığında yine baştan alıyoruz. Bu yolla kullanıcının fikir değiştirmesinin önünü açmış oluyoruz. Diğer türlü “bir daha asla sorma” kutusunu işaretlerse kararından geri dönemeyeceği için ona bu yolla fikir değiştirme özgürlüğü vermiş oluyouruz.

İzine evet derse bu sefer  2.diyalog kutusunda izin talebinde bulunuyoruz..

İkinci durumda, herhangi bir izin verme diyalogu olmadan onRequestPermissionsResultçağrılacaktır PERMISSION_DENIED.

rationaledialog

Buraya kadar olanlar kafa karıştırmaması için tek bir dosyada toplarsak;

package com.mobilprogramlar.ntzinal;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.NonNull;

public class Eeeeeee extends Activity {
    final private int ONAY_KODU = 1234;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.eeeeee);
        izin_Kontrolet_Al();
    }


    public void yapilacaklar() {
        Toast.makeText(getApplicationContext(), "yapilacaklar şunlar", Toast.LENGTH_LONG).show();
    }


    private void izin_Kontrolet_Al() {
        int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.CALL_PHONE);
        if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
            if (!shouldShowRequestPermissionRationale(Manifest.permission.CALL_PHONE)) {
                showMessageOKCancel("Çağrı için izin vermeniz gerekir", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                requestPermissions(new String[] {Manifest.permission.CALL_PHONE}, ONAY_KODU);
                            }
                        });
                return;
            }
            requestPermissions(new String[] {Manifest.permission.CALL_PHONE}, ONAY_KODU);
            return;
        }
        yapilacaklar();
    }
    private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(Eeeeeee.this)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", null)
                .create()
                .show();
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        //public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case ONAY_KODU: {
                // CALL_PHONE izni verilip verilmediğini kontrol edin
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(Eeeeeee.this, "CALL_PHONE izni VERİLDİ", Toast.LENGTH_SHORT).show();
                    yapilacaklar();
                } else {
                    Toast.makeText(Eeeeeee.this, "CALL_PHONE izni REDDEDİLDİ", Toast.LENGTH_SHORT).show();
                }
                break;
            }
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }

    }
}

Sonuç; önce isteyeceğimiz izin için bir pencere açarak sebebini anlatıyoruz. Tamam derse asıl izin penceresi çıkıyor ve izin talebinde bulunuyoruz.

Kullandığımız komutları özetlersek;

  • ContextCompat.checkSelfPermission () izni olup olmadığını kontrol etmek için verilir.
  • ActivityCompat.requestPermissions () izinleri istemek için. Birden fazla izin grubu ile birden fazla izin talep edilebilir.
  • ActivityCompat.shouldShowRequestPermissionRationale () , neden izin almak istediğine dair mantıklı bir mesaj göstermeye karar verdi.
  • onRequestPermissionsResult () , kullanıcının izin istemine verdiği yanıtı ele almak için.

    Buraya kadar anlatılanların çalışır haldeki kodlarını buradan Github hesabından indirebilirsiniz.

Bir seferde birden fazla izin istemek

Kesinlikle birden fazla izin gerektiren bazı özellikler var. Bir kerede yukarıdaki gibi aynı yöntemle birden fazla izin talep edebilirsiniz. Her neyse, her bir izin için de ‘Bir daha asla sorma’ durumunu kontrol etmeyi unutmayın.

Android.Manifest i unutmayalım;

    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

İşte revize edilmiş kod.

final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;

    private void insertDummyContactWrapper() {
        List<String> permissionsNeeded = new ArrayList<String>();

        final List<String> permissionsList = new ArrayList<String>();
        if (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
            permissionsNeeded.add("GPS");
        if (!addPermission(permissionsList, Manifest.permission.READ_CONTACTS))
            permissionsNeeded.add("Kişileri Oku");
        if (!addPermission(permissionsList, Manifest.permission.WRITE_CONTACTS))
            permissionsNeeded.add("Kişileri Yaz");

        if (permissionsList.size() > 0) {
            if (permissionsNeeded.size() > 0) {
                // Need Rationale
                String message = "Erişim izni vermeniz gerekiyor " + permissionsNeeded.get(0);
                for (int i = 1; i < permissionsNeeded.size(); i++)
                    message = message + ", " + permissionsNeeded.get(i);
                showMessageOKCancel(message,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                                        REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
                            }
                        });
                return;
            }
            requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                    REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
            return;
        }

        insertDummyContact();
    }

    private boolean addPermission(List<String> permissionsList, String permission) {
        if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
            permissionsList.add(permission);
            // Gerekçe Seçeneğini Denetle
            if (!shouldShowRequestPermissionRationale(permission))
                return false;
        }
        return true;
    }

Her bir izin verilen hibe sonucunu aldığında, sonuç aynı geri çağırma yöntemine gönderilir  onRequestPermissionsResult. Kaynak kodun daha temiz ve daha okunaklı görünmesi için HashMap kullanılabilir.

@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:
                {
                Map<String, Integer> perms = new HashMap<String, Integer>();
                // ilk
                perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.READ_CONTACTS, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.WRITE_CONTACTS, PackageManager.PERMISSION_GRANTED);
                // Sonuçları doldurun
                for (int i = 0; i < permissions.length; i++)
                    perms.put(permissions[i], grantResults[i]);
                // ACCESS_FINE_LOCATION için kontrol et
                if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                        && perms.get(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED
                        && perms.get(Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
                    // Tüm İzin Verildi
                    insertDummyContact();
                } else {
                    // İzin reddedildi
                    Toast.makeText(MainActivity.this, "Bazı İzin Reddedildi", Toast.LENGTH_SHORT)
                            .show();
                }
                }
                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

Kodların tamamın birarada;

package com.mobilprogramlar.uygulamazinleri2;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.DialogInterface;
import android.content.OperationApplicationException;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.util.Log;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MainActivity extends AppCompatActivity {
    final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;
    private static final String TAG = "İletişim";

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



    private void insertDummyContact() {
        // Yeni bir temas kurmak için iki işlem gerekir.
        ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(2);
        // İlk önce, yeni bir raw kişisi kur.
        ContentProviderOperation.Builder op =  ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null);
        operations.add(op.build());

        // Ardından, kişinin adını ayarlayın.
        op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
                        "__DUMMY CONTACT from runtime permissions sample");
        operations.add(op.build());

        // İşlemleri uygula.
        ContentResolver resolver = getContentResolver();
        try {
            resolver.applyBatch(ContactsContract.AUTHORITY, operations);
        } catch (RemoteException e) {
            Log.d(TAG, "Yeni bir kişi eklenemedi: " + e.getMessage());
        } catch (OperationApplicationException e) {
            Log.d(TAG, "Yeni bir kişi eklenemedi\n: " + e.getMessage());
        }
    }


    private void insertDummyContactWrapper() {
        List<String> permissionsNeeded = new ArrayList<String>();

        final List<String> permissionsList = new ArrayList<String>();
        if (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
            permissionsNeeded.add("GPS");
        if (!addPermission(permissionsList, Manifest.permission.READ_CONTACTS))
            permissionsNeeded.add("Kişileri Oku");
        if (!addPermission(permissionsList, Manifest.permission.WRITE_CONTACTS))
            permissionsNeeded.add("Kişileri Yaz");

        if (permissionsList.size() > 0) {
            if (permissionsNeeded.size() > 0) {
                // Need Rationale
                String message = "Erişim izni vermeniz gerekiyor " + permissionsNeeded.get(0);
                for (int i = 1; i < permissionsNeeded.size(); i++)
                    message = message + ", " + permissionsNeeded.get(i);
                showMessageOKCancel(message,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                                        REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
                            }
                        });
                return;
            }
            requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                    REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
            return;
        }

        insertDummyContact();
    }

    private boolean addPermission(List<String> permissionsList, String permission) {
        if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
            permissionsList.add(permission);
            // Gerekçe Seçeneğini Denetle
            if (!shouldShowRequestPermissionRationale(permission))
                return false;
        }
        return true;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:
            {
                Map<String, Integer> perms = new HashMap<String, Integer>();
                // ilk
                perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.READ_CONTACTS, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.WRITE_CONTACTS, PackageManager.PERMISSION_GRANTED);
                // Sonuçları doldurun
                for (int i = 0; i < permissions.length; i++)
                    perms.put(permissions[i], grantResults[i]);
                // ACCESS_FINE_LOCATION için kontrol et
                if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                        && perms.get(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED
                        && perms.get(Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
                    // Tüm İzin Verildi
                    insertDummyContact();
                } else {
                    // İzin reddedildi
                    Toast.makeText(MainActivity.this, "Bazı İzinler Reddedildi\n", Toast.LENGTH_SHORT).show();
                }
            }
            break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }






    private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(MainActivity.this)
                .setMessage(message)
                .setPositiveButton("Evet", okListener)
                .setNegativeButton("Hayır", null)
                .create()
                .show();
    }


}

Sonuç;

uygulamazinleri 2 1
uygulamazinleri 2 2
uygulamazinleri 2 3
uygulamazinleri 2 4

Bu kısımda  anlatılanların çalışır haldeki kodlarını buradan Github hesabından indirebilirsiniz.

Android 6.0 Marshmallow Öncesi

Yukarıdaki kod Android 6.0 Marshmallow’da mükemmel çalışıyor olmasına rağmen. Maalesef Android’in Marshmallow öncesi Android’inde çökmesine neden olacak, çünkü bu işlevler API Seviye 23’e eklenmiş.

Düz yol, Sürüm Sürümü’nü aşağıdaki kodla kontrol edebilmenizdir.

if (Build.VERSION.SDK_INT >= 23) {
            // Marshmallow+
        } else {
            // Pre-Marshmallow
        }

Ancak kod daha da karmaşık olacak. Bu yüzden , bu şey için hazırlanmış olan Support Library v4’ten biraz yardım almanızı öneririm . Bu işlevleri şununla değiştirin:

if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED){
//CALL_PHONE özelliği için kullanıcı zaten daha önceden yetki vermiştir. Bu yetki ile yapılmak istenen burada yapılır.
}
else {
// İzin için kullanıcıya açıkça sorulmalıdır.
}

İzinleri kontrol et

ContextCompat.checkSelfPermission()

İzniniz olup olmadığını kontrol etmek için ContextCompat.checkSelfPermission()yöntemi kullanın.

Örneğin, bu pasaj, etkinliğin takvime yazma izni olup olmadığını kontrol etmeyi gösterir:

if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR)!= PackageManager.PERMISSION_GRANTED) {
    // İzin verilmemiştir
}else {
    // İzin verilmiştir
}

Uygulama M üzerinde çalıştırılır veya çalıştırılmaz.

Bu metod kullanıcı izin verdiğinde PackageManager.PERMISSION_GRANTED dönerken,

izin vermediğinde ise PackageManager.PERMISSION_DENIED döner.

ActivityCompat.requestPermissions ()

ActivityCompat.requestPermissions ()

Bu fonksiyon M öncesi çağrılırsa, OnRequestPermissionsResultCallback, aniden doğru PERMISSION_GRANTED veya  PERMISSION_DENIED sonuç ile çağrılır  .

ActivityCompat.shouldShowRequestPermissionRationale ()

ActivityCompat.shouldShowRequestPermissionRationale ()

Bu fonksiyon Android MarshMallow öncesi çağrılırsa, her zaman false geri döner.

shouldShowRequestPermissionRationale()

Kullanıcıya daha önceden android standart dialog’u gösterilmiş ve kullanıcı izni onaylamamışsa  true döner

   HER ZAMAN Support Library v4 deki   checkSelfPermissionrequestPermissions ve  shouldShowRequestPermissionRationale fonksiyonlarını kullanmaya çalışın.

Bu şekilde uygulamanız aynı kod mantığına sahip herhangi bir Android sürümünde mükemmel bir şekilde çalışacaktır. Lütfen bu fonksiyonların bazı ek parametreler gerektirdiğini unutmayın: Context ya da Activity gibi.. Yapacak özel bir şey yok, sadece istediğini doğru bir şekilde iletin. İşte kaynak kod:

private void insertDummyContactWrapper() {
        int hasWriteContactsPermission = ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_CONTACTS);
        if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
            if (!ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.WRITE_CONTACTS)) {
                showMessageOKCancel("Rehber’e erişime izin vermeniz gerekir", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                ActivityCompat.requestPermissions(MainActivity.this, new String[] {Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_ASK_PERMISSIONS);
                            }
                        });
                return;
            }
            ActivityCompat.requestPermissions(MainActivity.this, new String[] {Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_ASK_PERMISSIONS);
            return;
        }
        insertDummyContact();
    }

Şu anda bu yeni izin sisteminin büyük resmini net bir şekilde gördüğünüze inanıyorum. Ve bunun ne kadar büyük bir sorun olduğunu da anladığınıza inanıyorum.

Ancak başka seçeneğiniz yok. Çalışma Zamanı İzni zaten Android Marshmallow’da kullanılıyor. Geri dönüşü olmayan noktadayız. Şu anda yapabileceğimiz tek şey, uygulamamızı bu yeni izin sistemini tam olarak desteklemektir.

İyi haber şu ki, Çalışma Zamanı İzni akışı gerektiren yalnızca birkaç izin var. Sık kullanılan izinlerin çoğu, örneğin, İNTERNET, Normal İzin’dedir , otomatik olarak verilir ve onlarla hiçbir şey yapmanıza gerek kalmaz. Sonuç olarak, değiştirmeniz gereken kodun sadece bir kısmı vardır.

Android ve AndroidX

   
Androidimport android.support.design.widget.CoordinatorLayout; 
AndroidXimport androidx.coordinatorlayout.widget.CoordinatorLayout; 
   
Androidimport android.support.design.widget.Snackbar; 
AndroidXimport com.google.android.material.snackbar.Snackbar; 
   
Androidimport android.support.v7.app.AppCompatActivity; 
AndroidXimport androidx.appcompat.app.AppCompatActivity; 
   
Android< android.support.design.widget.CoordinatorLayout</android.support.design.widget.CoordinatorLayout>
AndroidX<androidx.coordinatorlayout.widget.CoordinatorLayout</androidx.coordinatorlayout.widget.CoordinatorLayout>
   
Android<android.support.design.widget.FloatingActionButton 
AndroidX<com.google.android.material.floatingactionbutton.FloatingActionButton 
   
Androidimport android.support.annotation.ColorRes; 
AndroidXimport androidx.annotation.ColorRes; 
   
Androidimport android.support.annotation.DrawableRes; 
AndroidXimport androidx.annotation.DrawableRes; 
   
Androidimport android.support.annotation.NonNull; 
AndroidXimport androidx.annotation.NonNull; 
   
Androidimport android.support.annotation.DimenRes; 
AndroidXimport androidx.annotation.DimenRes; 
   
Androidimport android.support.annotation.IntDef; 
AndroidXimport androidx.annotation.IntDef; 
   
Android  
AndroidX  
   
Android  
AndroidX  
   
Android  
AndroidX  
   
Android  
AndroidX  
   
Android  
AndroidX  

android den androidX e geçiş rehberi;

 build.gradle 
Androidimplementation ‘android.support.v7.widget.Toolbar’ 
AndroidXimplementation ‘androidx.support.v7.widget.Toolbar’ 
   
Androidcom.android.support:coordinatorlayout 
AndroidXandroidx.coordinatorlayout:coordinatorlayout:1.0.0-alpha1 
   
Androidcom.android.support:appcompat-v7:23.1.1′ 
AndroidXandroidx.appcompat:appcompat:1.0.0 
   
   
   
   
   
   
   
   
   
   
   

Floating Action Button Behavior

Floating Action Button Behavior

 

gradle a alttaki satır eklenmeli;

implementation 'com.getbase:floatingactionbutton:1.10.1'

tamamı

apply plugin: 'com.android.application'
android {
    compileSdkVersion 28
    buildToolsVersion '28.0.3'
    defaultConfig {
        applicationId "com.mobilprogramlar.floatingactionbuttonbehavior"
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta2'
    testİmplementation 'junit:junit:4.13-beta-3'
    androidTestİmplementation 'androidx.test:runner:1.3.0-alpha02'
    androidTestİmplementation 'androidx.test.espresso:espresso-core:3.3.0-alpha02'
    implementation 'com.google.android.material:material:1.0.0'

    implementation 'com.getbase:floatingactionbutton:1.10.1'
}

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.getbase.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="16dp"
        app:fab_icon="@drawable/ic_done"
        app:layout_behavior="com.mobilprogramlar.floatingactionbuttonbehavior.FloatingActionButtonBehavior"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

MainActivity ise

package com.mobilprogramlar.floatingactionbuttonbehavior;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import com.google.android.material.snackbar.Snackbar;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Merhaba Snackbar", Snackbar.LENGTH_LONG).show();
            }
        });
    }
}

 

FloatingActionButtonBehavior.class

package com.mobilprogramlar.floatingactionbuttonbehavior;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;

public class FloatingActionButtonBehavior extends CoordinatorLayout.Behavior<FloatingActionButton> {

  public FloatingActionButtonBehavior(Context context, AttributeSet attrs) {
  }
  @Override
  public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
    return dependency instanceof Snackbar.SnackbarLayout;
  }
  @Override
  public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
    float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight());
    child.setTranslationY(translationY);
    return true;
  }
}

 

Son görünüm

floatingactionbuttonbehavior

 

Kodların tam çalışır halini Github hesabımdan indirebilirsinz.

 

CoordinatorLayout ile Float Button ve Snackbar

CoordinatorLayout ile Float ve Snackbar

CoordinatorLayout, Android Tasarım Destek Kütüphanesi ile tanıtılan yeni bir düzendir. CoordinatorLayout, süper güçlü bir FrameLayout’tur ( resmi belgelere göre ). Daha önce bir FrameLayout kullandıysanız, CoordinatorLayout’u kullanırken çok rahat olmalısınız. FrameLayout kullanmadıysanız, endişelenmeyin, oldukça kolay.
Varsayılan olarak, bir FrameLayout’a birden fazla çocuk eklerseniz birbirleriyle örtüşürler. Bir FrameLayout, en sık tek bir çocuk görüntüsü elde etmek için kullanılmalıdır. CoordinatorLayout’un ana çekiciliği, içerisindeki görüşlerin animasyonlarını ve geçişlerini koordine edebilmesidir. Yalnızca xml kullanarak, örneğin bir FAB’ın gelen bir Snackbar’ın dışına çıktığını, ya da görünüşe göre başka bir widget’a eklenmiş ve ekranda görünen bir FAB’ın (ya da gerçekten başka herhangi bir Görünümün) bulunduğu bir düzen tanımlayabilirsiniz. widget.

Bu makale için, CoordinatorLayout’u kullanmanın, görünümlerin diğer görünümlerin düzenindeki veya konumundaki değişikliklere yanıt vermesini sağlayarak kodunuzu basitleştirebileceği üç farklı yol göstereceğiz. Daha sonra, bu davranışın kodda nasıl elde edildiğini tartışacağız ve kendi özel davranışlarınızı görünümler arasında nasıl uygulayacağınızı öğrendiğiniz dördüncü bir yöntemi göstereceğiz. Özel davranışlar uygulayarak, yalnızca hayal gücünüzle (ve kodlama yeteneğinizle: D) sınırlandırılan kolayca birbirine bağlı inanılmaz animasyonlar, geçişler ve efektler oluşturabilirsiniz.

Uygulamanızda CoordinatorLayout’u kullanmadan önce, uygulamanızın aşağıdaki bağımlılığını ekleyerek Android Destek Tasarım Kitaplığını projenize içe aktarmanız gerekir.

Module kısmında app ye ait  build.gradle

apply plugin: 'com.android.application'
android {
    compileSdkVersion 28
    buildToolsVersion '28.0.3'
    defaultConfig {
        applicationId "com.mobilprogramlar.floatbutton1"
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    testİmplementation 'junit:junit:4.13-beta-3'
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support:design:28.0.0'

}

 

Snackbar ve FAB

İlk aktivite için, Snackbar görüntülendiğinde otomatik olarak kaybolan bir FAB ile düzen oluşturmak istiyoruz. Bu, CoordinatorLayout için bir “HelloWorld” programı ve iyi bir sebeple. İşlevsellik tamamen basit bir düzen olan xml dosyasında uygulanmıştır ve sadece çalışır.

Düzen oldukça basittir. CoordinatorLayout, kök düzendir. İçinde, ekran üzerinde ortalanmış bir düğmeye ve malzeme tasarım kurallarına uymamızı sağlamak için ekranın sağ alt köşesine yerleştirilmiş bir FAB’a sahibiz.

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/coordinatorLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.mobilprogramlar.floatbutton1.MainActivity">
    <Button
        android:id="@+id/showSnackbarButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="@string/show_snackbar"/>
    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|right"
        android:layout_marginBottom="@dimen/activity_vertical_margin"
        android:layout_marginEnd="@dimen/activity_horizontal_margin"
        android:src="@drawable/ic_done"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Activity sınıfına yaptığımız tek ekleme, Snackbar’ı göstermek için Düğmeye OnClickListener uygulamaktır. Snackbar’ın kök Görünümünü CoordinatorLayout olarak ayarladık. Bu şekilde, CoordinatorLayout Snackbar ve FAB hakkında bilgi sahibi olur ve her iki widget’in çakışmadığından emin olmak için geçiş animasyonu otomatik olarak yürütülür.

package com.mobilprogramlar.floatbutton1;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.snackbar.Snackbar;

public class MainActivity extends AppCompatActivity {
    private Button mShowSnackbarButton;
    private CoordinatorLayout mCoordinatorLayout;

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

        mCoordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinatorLayout);
        mShowSnackbarButton = (Button) findViewById(R.id.showSnackbarButton);
        mShowSnackbarButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(mCoordinatorLayout,
                        "Bu basit bir Snackbar", Snackbar.LENGTH_LONG)
                        .setAction("KAPAT", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                // Custom action
                            }
                        }).show();
            }
        });
    }
}

 

Aktiviteyi yürütün ve FAB’nin, gösterildiğinde, snackbar için otomatik olarak yukarı ve dışarı kaydığını ve snackbar görünümden çıkarken konumuna aşağı doğru kaydığını gözlemleyin.

String.xml

<resources>
    <string name="app_name">Float ve Snackbar</string>
    <string name="show_snackbar">Snackbarı Göster</string>
</resources>

 

dimens.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

 

Sonuç:

Float ve Snackbar

Kodların tam çalışır halini Github hesabımdan indirebilirsinz.

 

Floating Action Button (FAB) Nasıl Yapılır

Floating Action Button Nedir?

Malzeme Tasarımında tanıtılan yeni bir bileşen Floating Action Button (nedir).Sağ alt kısımdaki UI’nin üzerinde yüzen yüksek dairesel bir görünüştür. Genellikle, ekranın en önemli eylemini vurgulayan farklı görseliyle dikkat çeker.

float button

 

Bu nispeten basit eğitimde Web de genelde Lolipop öncesi örnekler mevcut ama Google ın getirdiği Api 26 zorunluluğu ile artık bütün apk ların yenilenmesi gerekmekte.

Floating action buttons (Kayan eylem düğmeleri) FAB, tanıtılan bir eylem için kullanılır. UI’nin üzerinde yüzen daire içine alınmış bir simge ile ayırt edilirler ve değişim, başlatma ve aktarma çapa noktası içeren hareket davranışları vardır. – Materyal Tasarımı kaynağı

Gradle ayarlarını aşağıdaki altı çizili yerlerden belirtilen değerlere göre ayarlayalım.

gradle ayar

 

Api leri ise yine aşağıdaki şekiilerdeki gibi …

module ayar 1

 

module ayar 2

 

Geldik dosyalara, önce activity_main

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1"
    tools:context=".MainActivity">

    <RelativeLayout
        android:background="@color/background"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <com.mobilprogramlar.floadnt.FloatingActionButton
            android:id="@+id/pink_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            app:fab_colorNormal="@color/pink"
            app:fab_icon="@drawable/ic_fab_star" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@id/pink_icon"
            android:text="Text below button"
            android:layout_centerHorizontal="true"
            style="@style/menu_labels_style"
            android:layout_marginBottom="48dp"/>

        <com.mobilprogramlar.floadnt.AddFloatingActionButton
            android:id="@+id/semi_transparent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="16dp"
            app:fab_colorNormal="@color/blue_semi_transparent"
            app:fab_colorPressed="@color/blue_semi_transparent_pressed"
            app:fab_plusIconColor="@color/white"
            />
        <com.mobilprogramlar.floadnt.FloatingActionButton
            android:id="@+id/setter"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@id/semi_transparent"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="16dp" />

        <com.mobilprogramlar.floadnt.AddFloatingActionButton
            android:id="@+id/normal_plus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            app:fab_colorNormal="@color/white"
            app:fab_colorPressed="@color/white_pressed"
            app:fab_plusIconColor="@color/half_black"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_marginBottom="16dp"
            android:layout_marginLeft="16dp"
            android:layout_marginStart="16dp"/>

        <com.mobilprogramlar.floadnt.FloatingActionsMenu
            android:id="@+id/right_labels"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_weight="1"
            app:fab_addButtonColorNormal="@color/white"
            app:fab_addButtonColorPressed="@color/white_pressed"
            app:fab_addButtonPlusIconColor="@color/half_black"
            app:fab_addButtonSize="mini"
            app:fab_labelStyle="@style/menu_labels_style"
            app:fab_labelsPosition="right"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_above="@id/normal_plus"
            android:layout_marginLeft="16dp">

            <com.mobilprogramlar.floadnt.FloatingActionButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:fab_colorNormal="@color/white"
                app:fab_colorPressed="@color/white_pressed"
                app:fab_title="Label on the right" />

            <com.mobilprogramlar.floadnt.FloatingActionButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:fab_colorNormal="@color/white"
                app:fab_colorPressed="@color/white_pressed"
                app:fab_size="mini"
                app:fab_title="Another one on the right" />

        </com.mobilprogramlar.floadnt.FloatingActionsMenu>

        <!-- -->

        <com.mobilprogramlar.floadnt.FloatingActionsMenu
            android:id="@+id/multiple_actions"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_alignParentEnd="true"
            app:fab_addButtonColorNormal="@color/white"
            app:fab_addButtonColorPressed="@color/white_pressed"
            app:fab_addButtonPlusIconColor="@color/half_black"
            app:fab_labelStyle="@style/menu_labels_style"
            android:layout_marginBottom="16dp"
            android:layout_marginRight="16dp"
            android:layout_marginEnd="16dp">

            <com.mobilprogramlar.floadnt.FloatingActionButton
                android:id="@+id/action_a"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:fab_colorNormal="@color/white"
                app:fab_colorPressed="@color/white_pressed"
                app:fab_title="Action Aaaaa" />

            <com.mobilprogramlar.floadnt.FloatingActionButton
                android:id="@+id/action_b"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:fab_colorNormal="@color/white"
                app:fab_colorPressed="@color/white_pressed"
                app:fab_title="Action with a very long name that won\'t fit on the screen" />
        </com.mobilprogramlar.floadnt.FloatingActionsMenu>

        <!-- -->

        <com.mobilprogramlar.floadnt.FloatingActionsMenu
            android:id="@+id/multiple_actions_down"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignParentEnd="true"
            android:layout_alignParentTop="true"
            android:layout_marginTop="16dp"
            android:layout_marginRight="16dp"
            android:layout_marginEnd="16dp"
            app:fab_addButtonColorNormal="@color/white"
            app:fab_addButtonColorPressed="@color/white_pressed"
            app:fab_addButtonPlusIconColor="@color/half_black"
            app:fab_addButtonSize="mini"
            app:fab_expandDirection="down"
            app:fab_labelStyle="@style/menu_labels_style">

            <com.mobilprogramlar.floadnt.FloatingActionButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:fab_colorNormal="@color/white"
                app:fab_colorPressed="@color/white_pressed"
                app:fab_size="mini" />

            <com.mobilprogramlar.floadnt.FloatingActionButton
                android:id="@+id/button_remove"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:fab_colorNormal="@color/white"
                app:fab_colorPressed="@color/white_pressed"
                app:fab_title="Click to remove" />

            <com.mobilprogramlar.floadnt.FloatingActionButton
                android:id="@+id/button_gone"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:fab_colorNormal="@color/white"
                app:fab_colorPressed="@color/white_pressed" />

            <com.mobilprogramlar.floadnt.FloatingActionButton
                android:id="@+id/action_enable"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:fab_colorNormal="@color/white"
                app:fab_colorPressed="@color/white_pressed"
                app:fab_title="Set bottom menu enabled/disabled" />
        </com.mobilprogramlar.floadnt.FloatingActionsMenu>

        <com.mobilprogramlar.floadnt.FloatingActionsMenu
            android:id="@+id/multiple_actions_left"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toLeftOf="@+id/multiple_actions_down"
            android:layout_toStartOf="@+id/multiple_actions_down"
            android:layout_alignParentTop="true"
            app:fab_addButtonColorNormal="@color/white"
            app:fab_addButtonColorPressed="@color/white_pressed"
            app:fab_addButtonPlusIconColor="@color/half_black"
            app:fab_addButtonSize="mini"
            app:fab_addButtonStrokeVisible="false"
            app:fab_expandDirection="left"
            android:layout_marginTop="16dp"
            android:layout_marginRight="16dp"
            android:layout_marginEnd="16dp">

            <com.mobilprogramlar.floadnt.FloatingActionButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:fab_colorNormal="@color/white"
                app:fab_colorPressed="@color/white_pressed" />

            <com.mobilprogramlar.floadnt.FloatingActionButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:fab_colorNormal="@color/white"
                app:fab_colorPressed="@color/white_pressed"
                app:fab_size="mini" />

            <com.mobilprogramlar.floadnt.FloatingActionButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:visibility="gone"
                app:fab_colorNormal="@color/white"
                app:fab_colorPressed="@color/white_pressed"
                app:fab_size="mini" />
        </com.mobilprogramlar.floadnt.FloatingActionsMenu>

        <com.mobilprogramlar.floadnt.FloatingActionButton
            android:id="@+id/setter_drawable"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@id/setter"
            android:layout_centerHorizontal="true" />
    </RelativeLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

 

Sıra java kodlarında bize yardımcı 4 adet java dosyamız var;

AddFloatingActionButton

package com.mobilprogramlar.floadnt;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.Shape;
import android.util.AttributeSet;
import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;

public class AddFloatingActionButton extends FloatingActionButton {
  int mPlusColor;

  public AddFloatingActionButton(Context context) {
    this(context, null);
  }

  public AddFloatingActionButton(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public AddFloatingActionButton(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
  }

  @Override
  void init(Context context, AttributeSet attributeSet) {
    TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.AddFloatingActionButton, 0, 0);
    mPlusColor = attr.getColor(R.styleable.AddFloatingActionButton_fab_plusIconColor, getColor(android.R.color.white));
    attr.recycle();
    super.init(context, attributeSet);
  }

  public int getPlusColor() {
    return mPlusColor;
  }

  public void setPlusColorResId(@ColorRes int plusColor) {
    setPlusColor(getColor(plusColor));
  }

  public void setPlusColor(int color) {
    if (mPlusColor != color) {
      mPlusColor = color;
      updateBackground();
    }
  }

  @Override
  public void setIcon(@DrawableRes int icon) {
    throw new UnsupportedOperationException("Use FloatingActionButton if you want to use custom icon");
  }

  @Override
  Drawable getIconDrawable() {
    final float iconSize = getDimension(R.dimen.fab_icon_size);
    final float iconHalfSize = iconSize / 2f;

    final float plusSize = getDimension(R.dimen.fab_plus_icon_size);
    final float plusHalfStroke = getDimension(R.dimen.fab_plus_icon_stroke) / 2f;
    final float plusOffset = (iconSize - plusSize) / 2f;

    final Shape shape = new Shape() {
      @Override
      public void draw(Canvas canvas, Paint paint) {
        canvas.drawRect(plusOffset, iconHalfSize - plusHalfStroke, iconSize - plusOffset, iconHalfSize + plusHalfStroke, paint);
        canvas.drawRect(iconHalfSize - plusHalfStroke, plusOffset, iconHalfSize + plusHalfStroke, iconSize - plusOffset, paint);
      }
    };
    ShapeDrawable drawable = new ShapeDrawable(shape);
    final Paint paint = drawable.getPaint();
    paint.setColor(mPlusColor);
    paint.setStyle(Style.FILL);
    paint.setAntiAlias(true);
    return drawable;
  }
}

 

FloatingActionButton dosyası

package com.mobilprogramlar.floadnt;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.ShapeDrawable.ShaderFactory;
import android.graphics.drawable.StateListDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.util.AttributeSet;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.annotation.ColorRes;
import androidx.annotation.DimenRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatImageButton;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

public class FloatingActionButton extends AppCompatImageButton {

  public static final int SIZE_NORMAL = 0;
  public static final int SIZE_MINI = 1;

  @Retention(RetentionPolicy.SOURCE)
  @IntDef({ SIZE_NORMAL, SIZE_MINI })
  public @interface FAB_SIZE {
  }

  int mColorNormal;
  int mColorPressed;
  int mColorDisabled;
  String mTitle;
  @DrawableRes
  private int mIcon;
  private Drawable mIconDrawable;
  private int mSize;
  private float mCircleSize;
  private float mShadowRadius;
  private float mShadowOffset;
  private int mDrawableSize;
  boolean mStrokeVisible;

  public FloatingActionButton(Context context) {
    this(context, null);
  }

  public FloatingActionButton(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs);
  }

  public FloatingActionButton(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context, attrs);
  }

  void init(Context context, AttributeSet attributeSet) {
    TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionButton, 0, 0);
    mColorNormal = attr.getColor(R.styleable.FloatingActionButton_fab_colorNormal, getColor(android.R.color.holo_blue_dark));
    mColorPressed = attr.getColor(R.styleable.FloatingActionButton_fab_colorPressed, getColor(android.R.color.holo_blue_light));
    mColorDisabled = attr.getColor(R.styleable.FloatingActionButton_fab_colorDisabled, getColor(android.R.color.darker_gray));
    mSize = attr.getInt(R.styleable.FloatingActionButton_fab_size, SIZE_NORMAL);
    mIcon = attr.getResourceId(R.styleable.FloatingActionButton_fab_icon, 0);
    mTitle = attr.getString(R.styleable.FloatingActionButton_fab_title);
    mStrokeVisible = attr.getBoolean(R.styleable.FloatingActionButton_fab_stroke_visible, true);
    attr.recycle();

    updateCircleSize();
    mShadowRadius = getDimension(R.dimen.fab_shadow_radius);
    mShadowOffset = getDimension(R.dimen.fab_shadow_offset);
    updateDrawableSize();
    updateBackground();
  }

  private void updateDrawableSize() {
    mDrawableSize = (int) (mCircleSize + 2 * mShadowRadius);
  }

  private void updateCircleSize() {
    mCircleSize = getDimension(mSize == SIZE_NORMAL ? R.dimen.fab_size_normal : R.dimen.fab_size_mini);
  }

  public void setSize(@FAB_SIZE int size) {
    if (size != SIZE_MINI && size != SIZE_NORMAL) {
      throw new IllegalArgumentException("Use @FAB_SIZE constants only!");
    }

    if (mSize != size) {
      mSize = size;
      updateCircleSize();
      updateDrawableSize();
      updateBackground();
    }
  }

  @FAB_SIZE
  public int getSize() {
    return mSize;
  }

  public void setIcon(@DrawableRes int icon) {
    if (mIcon != icon) {
      mIcon = icon;
      mIconDrawable = null;
      updateBackground();
    }
  }

  public void setIconDrawable(@NonNull Drawable iconDrawable) {
    if (mIconDrawable != iconDrawable) {
      mIcon = 0;
      mIconDrawable = iconDrawable;
      updateBackground();
    }
  }

  public int getColorNormal() {
    return mColorNormal;
  }

  public void setColorNormalResId(@ColorRes int colorNormal) {
    setColorNormal(getColor(colorNormal));
  }

  public void setColorNormal(int color) {
    if (mColorNormal != color) {
      mColorNormal = color;
      updateBackground();
    }
  }

  public int getColorPressed() {
    return mColorPressed;
  }

  public void setColorPressedResId(@ColorRes int colorPressed) {
    setColorPressed(getColor(colorPressed));
  }

  public void setColorPressed(int color) {
    if (mColorPressed != color) {
      mColorPressed = color;
      updateBackground();
    }
  }

  public int getColorDisabled() {
    return mColorDisabled;
  }

  public void setColorDisabledResId(@ColorRes int colorDisabled) {
    setColorDisabled(getColor(colorDisabled));
  }

  public void setColorDisabled(int color) {
    if (mColorDisabled != color) {
        mColorDisabled = color;
        updateBackground();
    }
  }

  public void setStrokeVisible(boolean visible) {
    if (mStrokeVisible != visible) {
      mStrokeVisible = visible;
      updateBackground();
    }
  }

  public boolean isStrokeVisible() {
    return mStrokeVisible;
  }

  int getColor(@ColorRes int id) {
    return getResources().getColor(id);
  }

  float getDimension(@DimenRes int id) {
    return getResources().getDimension(id);
  }

  public void setTitle(String title) {
    mTitle = title;
    TextView label = getLabelView();
    if (label != null) {
      label.setText(title);
    }
  }

  TextView getLabelView() {
    return (TextView) getTag(R.id.fab_label);
  }

  public String getTitle() {
    return mTitle;
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    setMeasuredDimension(mDrawableSize, mDrawableSize);
  }

  void updateBackground() {
    final float strokeWidth = getDimension(R.dimen.fab_stroke_width);
    final float halfStrokeWidth = strokeWidth / 2f;

    LayerDrawable layerDrawable = new LayerDrawable(
        new Drawable[] {
            getResources().getDrawable(mSize == SIZE_NORMAL ? R.drawable.fab_bg_normal : R.drawable.fab_bg_mini),
            createFillDrawable(strokeWidth),
            createOuterStrokeDrawable(strokeWidth),
            getIconDrawable()
        });

    int iconOffset = (int) (mCircleSize - getDimension(R.dimen.fab_icon_size)) / 2;
    int circleInsetHorizontal = (int) (mShadowRadius);
    int circleInsetTop = (int) (mShadowRadius - mShadowOffset);
    int circleInsetBottom = (int) (mShadowRadius + mShadowOffset);

    layerDrawable.setLayerInset(1,
        circleInsetHorizontal,
        circleInsetTop,
        circleInsetHorizontal,
        circleInsetBottom);

    layerDrawable.setLayerInset(2,
        (int) (circleInsetHorizontal - halfStrokeWidth),
        (int) (circleInsetTop - halfStrokeWidth),
        (int) (circleInsetHorizontal - halfStrokeWidth),
        (int) (circleInsetBottom - halfStrokeWidth));

    layerDrawable.setLayerInset(3,
        circleInsetHorizontal + iconOffset,
        circleInsetTop + iconOffset,
        circleInsetHorizontal + iconOffset,
        circleInsetBottom + iconOffset);

    setBackgroundCompat(layerDrawable);
  }

  Drawable getIconDrawable() {
    if (mIconDrawable != null) {
      return mIconDrawable;
    } else if (mIcon != 0) {
      return getResources().getDrawable(mIcon);
    } else {
      return new ColorDrawable(Color.TRANSPARENT);
    }
  }

  private StateListDrawable createFillDrawable(float strokeWidth) {
    StateListDrawable drawable = new StateListDrawable();
    drawable.addState(new int[] { -android.R.attr.state_enabled }, createCircleDrawable(mColorDisabled, strokeWidth));
    drawable.addState(new int[] { android.R.attr.state_pressed }, createCircleDrawable(mColorPressed, strokeWidth));
    drawable.addState(new int[] { }, createCircleDrawable(mColorNormal, strokeWidth));
    return drawable;
  }

  private Drawable createCircleDrawable(int color, float strokeWidth) {
    int alpha = Color.alpha(color);
    int opaqueColor = opaque(color);
    ShapeDrawable fillDrawable = new ShapeDrawable(new OvalShape());

    final Paint paint = fillDrawable.getPaint();
    paint.setAntiAlias(true);
    paint.setColor(opaqueColor);

    Drawable[] layers = {
        fillDrawable,
        createInnerStrokesDrawable(opaqueColor, strokeWidth)
    };

    LayerDrawable drawable = alpha == 255 || !mStrokeVisible
        ? new LayerDrawable(layers)
        : new TranslucentLayerDrawable(alpha, layers);

    int halfStrokeWidth = (int) (strokeWidth / 2f);
    drawable.setLayerInset(1, halfStrokeWidth, halfStrokeWidth, halfStrokeWidth, halfStrokeWidth);

    return drawable;
  }

  private static class TranslucentLayerDrawable extends LayerDrawable {
    private final int mAlpha;

    public TranslucentLayerDrawable(int alpha, Drawable... layers) {
      super(layers);
      mAlpha = alpha;
    }

    @Override
    public void draw(Canvas canvas) {
      Rect bounds = getBounds();
      canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, mAlpha, Canvas.ALL_SAVE_FLAG);
      super.draw(canvas);
      canvas.restore();
    }
  }

  private Drawable createOuterStrokeDrawable(float strokeWidth) {
    ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape());

    final Paint paint = shapeDrawable.getPaint();
    paint.setAntiAlias(true);
    paint.setStrokeWidth(strokeWidth);
    paint.setStyle(Style.STROKE);
    paint.setColor(Color.BLACK);
    paint.setAlpha(opacityToAlpha(0.02f));
    return shapeDrawable;
  }

  private int opacityToAlpha(float opacity) {
    return (int) (255f * opacity);
  }

  private int darkenColor(int argb) {
    return adjustColorBrightness(argb, 0.9f);
  }

  private int lightenColor(int argb) {
    return adjustColorBrightness(argb, 1.1f);
  }

  private int adjustColorBrightness(int argb, float factor) {
    float[] hsv = new float[3];
    Color.colorToHSV(argb, hsv);

    hsv[2] = Math.min(hsv[2] * factor, 1f);

    return Color.HSVToColor(Color.alpha(argb), hsv);
  }

  private int halfTransparent(int argb) {
    return Color.argb(
        Color.alpha(argb) / 2,
        Color.red(argb),
        Color.green(argb),
        Color.blue(argb)
    );
  }

  private int opaque(int argb) {
    return Color.rgb(
        Color.red(argb),
        Color.green(argb),
        Color.blue(argb)
    );
  }

  private Drawable createInnerStrokesDrawable(final int color, float strokeWidth) {
    if (!mStrokeVisible) {
      return new ColorDrawable(Color.TRANSPARENT);
    }

    ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape());

    final int bottomStrokeColor = darkenColor(color);
    final int bottomStrokeColorHalfTransparent = halfTransparent(bottomStrokeColor);
    final int topStrokeColor = lightenColor(color);
    final int topStrokeColorHalfTransparent = halfTransparent(topStrokeColor);

    final Paint paint = shapeDrawable.getPaint();
    paint.setAntiAlias(true);
    paint.setStrokeWidth(strokeWidth);
    paint.setStyle(Style.STROKE);
    shapeDrawable.setShaderFactory(new ShaderFactory() {
      @Override
      public Shader resize(int width, int height) {
        return new LinearGradient(width / 2, 0, width / 2, height,
            new int[] { topStrokeColor, topStrokeColorHalfTransparent, color, bottomStrokeColorHalfTransparent, bottomStrokeColor },
            new float[] { 0f, 0.2f, 0.5f, 0.8f, 1f },
            TileMode.CLAMP
        );
      }
    });

    return shapeDrawable;
  }

  @SuppressWarnings("deprecation")
  @SuppressLint("NewApi")
  private void setBackgroundCompat(Drawable drawable) {
    if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
      setBackground(drawable);
    } else {
      setBackgroundDrawable(drawable);
    }
  }

  @Override
  public void setVisibility(int visibility) {
    TextView label = getLabelView();
    if (label != null) {
      label.setVisibility(visibility);
    }

    super.setVisibility(visibility);
  }
}

 

FloatingActionsMenu

package com.mobilprogramlar.floadnt;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.ColorRes;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;

public class FloatingActionsMenu extends ViewGroup {
  public static final int EXPAND_UP = 0;
  public static final int EXPAND_DOWN = 1;
  public static final int EXPAND_LEFT = 2;
  public static final int EXPAND_RIGHT = 3;
  public static final int LABELS_ON_LEFT_SIDE = 0;
  public static final int LABELS_ON_RIGHT_SIDE = 1;

  private static final int ANIMATION_DURATION = 300;
  private static final float COLLAPSED_PLUS_ROTATION = 0f;
  private static final float EXPANDED_PLUS_ROTATION = 90f + 45f;

  private int mAddButtonPlusColor;
  private int mAddButtonColorNormal;
  private int mAddButtonColorPressed;
  private int mAddButtonSize;
  private boolean mAddButtonStrokeVisible;
  private int mExpandDirection;
  private int mButtonSpacing;
  private int mLabelsMargin;
  private int mLabelsVerticalOffset;
  private boolean mExpanded;
  private AnimatorSet mExpandAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
  private AnimatorSet mCollapseAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
  private AddFloatingActionButton mAddButton;
  private RotatingDrawable mRotatingDrawable;
  private int mMaxButtonWidth;
  private int mMaxButtonHeight;
  private int mLabelsStyle;
  private int mLabelsPosition;
  private int mButtonsCount;

  private TouchDelegateGroup mTouchDelegateGroup;
  private OnFloatingActionsMenuUpdateListener mListener;

  public interface OnFloatingActionsMenuUpdateListener {
    void onMenuExpanded();
    void onMenuCollapsed();
  }

  public FloatingActionsMenu(Context context) {
    this(context, null);
  }

  public FloatingActionsMenu(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs);
  }

  public FloatingActionsMenu(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context, attrs);
  }

  private void init(Context context, AttributeSet attributeSet) {
    mButtonSpacing = (int) (getResources().getDimension(R.dimen.fab_actions_spacing) - getResources().getDimension(R.dimen.fab_shadow_radius) - getResources().getDimension(R.dimen.fab_shadow_offset));
    mLabelsMargin = getResources().getDimensionPixelSize(R.dimen.fab_labels_margin);
    mLabelsVerticalOffset = getResources().getDimensionPixelSize(R.dimen.fab_shadow_offset);

    mTouchDelegateGroup = new TouchDelegateGroup(this);
    setTouchDelegate(mTouchDelegateGroup);

    TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionsMenu, 0, 0);

    mAddButtonPlusColor = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonPlusIconColor, getColorWrapper(context,android.R.color.white));
    mAddButtonColorNormal = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonColorNormal, getColorWrapper(context,android.R.color.holo_blue_dark));
    mAddButtonColorPressed = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonColorPressed, getColorWrapper(context,android.R.color.holo_blue_light));

    mAddButtonSize = attr.getInt(R.styleable.FloatingActionsMenu_fab_addButtonSize, FloatingActionButton.SIZE_NORMAL);
    mAddButtonStrokeVisible = attr.getBoolean(R.styleable.FloatingActionsMenu_fab_addButtonStrokeVisible, true);
    mExpandDirection = attr.getInt(R.styleable.FloatingActionsMenu_fab_expandDirection, EXPAND_UP);
    mLabelsStyle = attr.getResourceId(R.styleable.FloatingActionsMenu_fab_labelStyle, 0);
    mLabelsPosition = attr.getInt(R.styleable.FloatingActionsMenu_fab_labelsPosition, LABELS_ON_LEFT_SIDE);
    attr.recycle();

    if (mLabelsStyle != 0 && expandsHorizontally()) {
      throw new IllegalStateException("Action labels in horizontal expand orientation is not supported.");
    }
    createAddButton(context);
  }

  public void setOnFloatingActionsMenuUpdateListener(OnFloatingActionsMenuUpdateListener listener) {
    mListener = listener;
  }

  private boolean expandsHorizontally() {
    return mExpandDirection == EXPAND_LEFT || mExpandDirection == EXPAND_RIGHT;
  }

  private static class RotatingDrawable extends LayerDrawable {
    public RotatingDrawable(Drawable drawable) {
      super(new Drawable[] { drawable });
    }

    private float mRotation;

    @SuppressWarnings("UnusedDeclaration")
    public float getRotation() {
      return mRotation;
    }

    @SuppressWarnings("UnusedDeclaration")
    public void setRotation(float rotation) {
      mRotation = rotation;
      invalidateSelf();
    }

    @Override
    public void draw(Canvas canvas) {
      canvas.save();
      canvas.rotate(mRotation, getBounds().centerX(), getBounds().centerY());
      super.draw(canvas);
      canvas.restore();
    }
  }

  private void createAddButton(Context context) {
    mAddButton = new AddFloatingActionButton(context) {
      @Override
      void updateBackground() {
        mPlusColor = mAddButtonPlusColor;
        mColorNormal = mAddButtonColorNormal;
        mColorPressed = mAddButtonColorPressed;
        mStrokeVisible = mAddButtonStrokeVisible;
        super.updateBackground();
      }

      @Override
      Drawable getIconDrawable() {
        final RotatingDrawable rotatingDrawable = new RotatingDrawable(super.getIconDrawable());
        mRotatingDrawable = rotatingDrawable;
        final OvershootInterpolator interpolator = new OvershootInterpolator();
        final ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", EXPANDED_PLUS_ROTATION, COLLAPSED_PLUS_ROTATION);
        final ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", COLLAPSED_PLUS_ROTATION, EXPANDED_PLUS_ROTATION);
        collapseAnimator.setInterpolator(interpolator);
        expandAnimator.setInterpolator(interpolator);

        mExpandAnimation.play(expandAnimator);
        mCollapseAnimation.play(collapseAnimator);
        return rotatingDrawable;
      }
    };

    mAddButton.setId(R.id.fab_expand_menu_button);
    mAddButton.setSize(mAddButtonSize);
    mAddButton.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        toggle();
      }
    });

    addView(mAddButton, super.generateDefaultLayoutParams());
    mButtonsCount++;
  }

  public void addButton(FloatingActionButton button) {
    addView(button, mButtonsCount - 1);
    mButtonsCount++;

    if (mLabelsStyle != 0) {
      createLabels();
    }
  }

  public void removeButton(FloatingActionButton button) {
    removeView(button.getLabelView());
    removeView(button);
    button.setTag(R.id.fab_label, null);
    mButtonsCount--;
  }

  private static int getColorWrapper(Context context, int id) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
      return context.getColor(id);
    } else {
      return context.getResources().getColor(id);
    }
  }



  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    measureChildren(widthMeasureSpec, heightMeasureSpec);
    int width = 0;
    int height = 0;
    mMaxButtonWidth = 0;
    mMaxButtonHeight = 0;
    int maxLabelWidth = 0;

    for (int i = 0; i < mButtonsCount; i++) {
      View child = getChildAt(i);
      if (child.getVisibility() == GONE) {
        continue;
      }
      switch (mExpandDirection) {
      case EXPAND_UP:
      case EXPAND_DOWN:
        mMaxButtonWidth = Math.max(mMaxButtonWidth, child.getMeasuredWidth());
        height += child.getMeasuredHeight();
        break;
      case EXPAND_LEFT:
      case EXPAND_RIGHT:
        width += child.getMeasuredWidth();
        mMaxButtonHeight = Math.max(mMaxButtonHeight, child.getMeasuredHeight());
        break;
      }

      if (!expandsHorizontally()) {
        TextView label = (TextView) child.getTag(R.id.fab_label);
        if (label != null) {
          maxLabelWidth = Math.max(maxLabelWidth, label.getMeasuredWidth());
        }
      }
    }

    if (!expandsHorizontally()) {
      width = mMaxButtonWidth + (maxLabelWidth > 0 ? maxLabelWidth + mLabelsMargin : 0);
    } else {
      height = mMaxButtonHeight;
    }

    switch (mExpandDirection) {
    case EXPAND_UP:
    case EXPAND_DOWN:
      height += mButtonSpacing * (mButtonsCount - 1);
      height = adjustForOvershoot(height);
      break;
    case EXPAND_LEFT:
    case EXPAND_RIGHT:
      width += mButtonSpacing * (mButtonsCount - 1);
      width = adjustForOvershoot(width);
      break;
    }

    setMeasuredDimension(width, height);
  }

  private int adjustForOvershoot(int dimension) {
    return dimension * 12 / 10;
  }

  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    switch (mExpandDirection) {
    case EXPAND_UP:
    case EXPAND_DOWN:
      boolean expandUp = mExpandDirection == EXPAND_UP;

      if (changed) {
        mTouchDelegateGroup.clearTouchDelegates();
      }

      int addButtonY = expandUp ? b - t - mAddButton.getMeasuredHeight() : 0;
      int buttonsHorizontalCenter = mLabelsPosition == LABELS_ON_LEFT_SIDE
          ? r - l - mMaxButtonWidth / 2
          : mMaxButtonWidth / 2;
      int addButtonLeft = buttonsHorizontalCenter - mAddButton.getMeasuredWidth() / 2;
      mAddButton.layout(addButtonLeft, addButtonY, addButtonLeft + mAddButton.getMeasuredWidth(), addButtonY + mAddButton.getMeasuredHeight());

      int labelsOffset = mMaxButtonWidth / 2 + mLabelsMargin;
      int labelsXNearButton = mLabelsPosition == LABELS_ON_LEFT_SIDE
          ? buttonsHorizontalCenter - labelsOffset
          : buttonsHorizontalCenter + labelsOffset;

      int nextY = expandUp ?
          addButtonY - mButtonSpacing :
          addButtonY + mAddButton.getMeasuredHeight() + mButtonSpacing;

      for (int i = mButtonsCount - 1; i >= 0; i--) {
        final View child = getChildAt(i);

        if (child == mAddButton || child.getVisibility() == GONE) continue;

        int childX = buttonsHorizontalCenter - child.getMeasuredWidth() / 2;
        int childY = expandUp ? nextY - child.getMeasuredHeight() : nextY;
        child.layout(childX, childY, childX + child.getMeasuredWidth(), childY + child.getMeasuredHeight());

        float collapsedTranslation = addButtonY - childY;
        float expandedTranslation = 0f;
        child.setTranslationY(mExpanded ? expandedTranslation : collapsedTranslation);
        child.setAlpha(mExpanded ? 1f : 0f);

        LayoutParams params = (LayoutParams) child.getLayoutParams();
        params.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation);
        params.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation);
        params.setAnimationsTarget(child);

        View label = (View) child.getTag(R.id.fab_label);
        if (label != null) {
          int labelXAwayFromButton = mLabelsPosition == LABELS_ON_LEFT_SIDE
              ? labelsXNearButton - label.getMeasuredWidth()
              : labelsXNearButton + label.getMeasuredWidth();

          int labelLeft = mLabelsPosition == LABELS_ON_LEFT_SIDE
              ? labelXAwayFromButton
              : labelsXNearButton;

          int labelRight = mLabelsPosition == LABELS_ON_LEFT_SIDE
              ? labelsXNearButton
              : labelXAwayFromButton;

          int labelTop = childY - mLabelsVerticalOffset + (child.getMeasuredHeight() - label.getMeasuredHeight()) / 2;
          label.layout(labelLeft, labelTop, labelRight, labelTop + label.getMeasuredHeight());
          Rect touchArea = new Rect(
              Math.min(childX, labelLeft),
              childY - mButtonSpacing / 2,
              Math.max(childX + child.getMeasuredWidth(), labelRight),
              childY + child.getMeasuredHeight() + mButtonSpacing / 2);
          mTouchDelegateGroup.addTouchDelegate(new TouchDelegate(touchArea, child));

          label.setTranslationY(mExpanded ? expandedTranslation : collapsedTranslation);
          label.setAlpha(mExpanded ? 1f : 0f);

          LayoutParams labelParams = (LayoutParams) label.getLayoutParams();
          labelParams.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation);
          labelParams.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation);
          labelParams.setAnimationsTarget(label);
        }

        nextY = expandUp ?
            childY - mButtonSpacing :
            childY + child.getMeasuredHeight() + mButtonSpacing;
      }
      break;

    case EXPAND_LEFT:
    case EXPAND_RIGHT:
      boolean expandLeft = mExpandDirection == EXPAND_LEFT;

      int addButtonX = expandLeft ? r - l - mAddButton.getMeasuredWidth() : 0;
      int addButtonTop = b - t - mMaxButtonHeight + (mMaxButtonHeight - mAddButton.getMeasuredHeight()) / 2;
      mAddButton.layout(addButtonX, addButtonTop, addButtonX + mAddButton.getMeasuredWidth(), addButtonTop + mAddButton.getMeasuredHeight());

      int nextX = expandLeft ?
          addButtonX - mButtonSpacing :
          addButtonX + mAddButton.getMeasuredWidth() + mButtonSpacing;

      for (int i = mButtonsCount - 1; i >= 0; i--) {
        final View child = getChildAt(i);
        if (child == mAddButton || child.getVisibility() == GONE) continue;
        int childX = expandLeft ? nextX - child.getMeasuredWidth() : nextX;
        int childY = addButtonTop + (mAddButton.getMeasuredHeight() - child.getMeasuredHeight()) / 2;
        child.layout(childX, childY, childX + child.getMeasuredWidth(), childY + child.getMeasuredHeight());

        float collapsedTranslation = addButtonX - childX;
        float expandedTranslation = 0f;
        child.setTranslationX(mExpanded ? expandedTranslation : collapsedTranslation);
        child.setAlpha(mExpanded ? 1f : 0f);

        LayoutParams params = (LayoutParams) child.getLayoutParams();
        params.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation);
        params.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation);
        params.setAnimationsTarget(child);
        nextX = expandLeft ?
            childX - mButtonSpacing :
            childX + child.getMeasuredWidth() + mButtonSpacing;
      }
      break;
    }
  }

  @Override
  protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
    return new LayoutParams(super.generateDefaultLayoutParams());
  }

  @Override
  public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
    return new LayoutParams(super.generateLayoutParams(attrs));
  }

  @Override
  protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
    return new LayoutParams(super.generateLayoutParams(p));
  }

  @Override
  protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
    return super.checkLayoutParams(p);
  }

  private static Interpolator sExpandInterpolator = new OvershootInterpolator();
  private static Interpolator sCollapseInterpolator = new DecelerateInterpolator(3f);
  private static Interpolator sAlphaExpandInterpolator = new DecelerateInterpolator();

  private class LayoutParams extends ViewGroup.LayoutParams {

    private ObjectAnimator mExpandDir = new ObjectAnimator();
    private ObjectAnimator mExpandAlpha = new ObjectAnimator();
    private ObjectAnimator mCollapseDir = new ObjectAnimator();
    private ObjectAnimator mCollapseAlpha = new ObjectAnimator();
    private boolean animationsSetToPlay;

    public LayoutParams(ViewGroup.LayoutParams source) {
      super(source);

      mExpandDir.setInterpolator(sExpandInterpolator);
      mExpandAlpha.setInterpolator(sAlphaExpandInterpolator);
      mCollapseDir.setInterpolator(sCollapseInterpolator);
      mCollapseAlpha.setInterpolator(sCollapseInterpolator);
      mCollapseAlpha.setProperty(View.ALPHA);
      mCollapseAlpha.setFloatValues(1f, 0f);
      mExpandAlpha.setProperty(View.ALPHA);
      mExpandAlpha.setFloatValues(0f, 1f);

      switch (mExpandDirection) {
      case EXPAND_UP:
      case EXPAND_DOWN:
        mCollapseDir.setProperty(View.TRANSLATION_Y);
        mExpandDir.setProperty(View.TRANSLATION_Y);
        break;
      case EXPAND_LEFT:
      case EXPAND_RIGHT:
        mCollapseDir.setProperty(View.TRANSLATION_X);
        mExpandDir.setProperty(View.TRANSLATION_X);
        break;
      }
    }

    public void setAnimationsTarget(View view) {
      mCollapseAlpha.setTarget(view);
      mCollapseDir.setTarget(view);
      mExpandAlpha.setTarget(view);
      mExpandDir.setTarget(view);

      // Now that the animations have targets, set them to be played
      if (!animationsSetToPlay) {
        addLayerTypeListener(mExpandDir, view);
        addLayerTypeListener(mCollapseDir, view);
        mCollapseAnimation.play(mCollapseAlpha);
        mCollapseAnimation.play(mCollapseDir);
        mExpandAnimation.play(mExpandAlpha);
        mExpandAnimation.play(mExpandDir);
        animationsSetToPlay = true;
      }
    }

    private void addLayerTypeListener(Animator animator, final View view) {
      animator.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
          view.setLayerType(LAYER_TYPE_NONE, null);
        }

        @Override
        public void onAnimationStart(Animator animation) {
          view.setLayerType(LAYER_TYPE_HARDWARE, null);
        }
      });
    }
  }

  @Override
  protected void onFinishInflate() {
    super.onFinishInflate();

    bringChildToFront(mAddButton);
    mButtonsCount = getChildCount();

    if (mLabelsStyle != 0) {
      createLabels();
    }
  }

  private void createLabels() {
    Context context = new ContextThemeWrapper(getContext(), mLabelsStyle);

    for (int i = 0; i < mButtonsCount; i++) {
      FloatingActionButton button = (FloatingActionButton) getChildAt(i);
      String title = button.getTitle();

      if (button == mAddButton || title == null ||
          button.getTag(R.id.fab_label) != null) continue;

      TextView label = new TextView(context);
      label.setTextAppearance(getContext(), mLabelsStyle);
      label.setText(button.getTitle());
      addView(label);
      button.setTag(R.id.fab_label, label);
    }
  }

  public void collapse() {
    collapse(false);
  }
  public void collapseImmediately() {
    collapse(true);
  }
  private void collapse(boolean immediately) {
    if (mExpanded) {
      mExpanded = false;
      mTouchDelegateGroup.setEnabled(false);
      mCollapseAnimation.setDuration(immediately ? 0 : ANIMATION_DURATION);
      mCollapseAnimation.start();
      mExpandAnimation.cancel();

      if (mListener != null) {
        mListener.onMenuCollapsed();
      }
    }
  }

  public void toggle() {
    if (mExpanded) {
      collapse();
    } else {
      expand();
    }
  }

  public void expand() {
    if (!mExpanded) {
      mExpanded = true;
      mTouchDelegateGroup.setEnabled(true);
      mCollapseAnimation.cancel();
      mExpandAnimation.start();

      if (mListener != null) {
        mListener.onMenuExpanded();
      }
    }
  }

  public boolean isExpanded() {
    return mExpanded;
  }

  @Override
  public void setEnabled(boolean enabled) {
    super.setEnabled(enabled);
    mAddButton.setEnabled(enabled);
  }

  @Override
  public Parcelable onSaveInstanceState() {
    Parcelable superState = super.onSaveInstanceState();
    SavedState savedState = new SavedState(superState);
    savedState.mExpanded = mExpanded;
    return savedState;
  }

  @Override
  public void onRestoreInstanceState(Parcelable state) {
    if (state instanceof SavedState) {
      SavedState savedState = (SavedState) state;
      mExpanded = savedState.mExpanded;
      mTouchDelegateGroup.setEnabled(mExpanded);

      if (mRotatingDrawable != null) {
        mRotatingDrawable.setRotation(mExpanded ? EXPANDED_PLUS_ROTATION : COLLAPSED_PLUS_ROTATION);
      }

      super.onRestoreInstanceState(savedState.getSuperState());
    } else {
      super.onRestoreInstanceState(state);
    }
  }

  public static class SavedState extends BaseSavedState {
    public boolean mExpanded;
    public SavedState(Parcelable parcel) {
      super(parcel);
    }

    private SavedState(Parcel in) {
      super(in);
      mExpanded = in.readInt() == 1;
    }

    @Override
    public void writeToParcel(@NonNull Parcel out, int flags) {
      super.writeToParcel(out, flags);
      out.writeInt(mExpanded ? 1 : 0);
    }

    public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
      @Override
      public SavedState createFromParcel(Parcel in) {
        return new SavedState(in);
      }

      @Override
      public SavedState[] newArray(int size) {
        return new SavedState[size];
      }
    };
  }
}

 

TouchDelegateGroup

package com.mobilprogramlar.floadnt;

import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.TouchDelegate;
import android.view.View;
import androidx.annotation.NonNull;
import java.util.ArrayList;

public class TouchDelegateGroup extends TouchDelegate {
  private static final Rect USELESS_HACKY_RECT = new Rect();
  private final ArrayList<TouchDelegate> mTouchDelegates = new ArrayList<TouchDelegate>();
  private TouchDelegate mCurrentTouchDelegate;
  private boolean mEnabled;

  public TouchDelegateGroup(View uselessHackyView) {
    super(USELESS_HACKY_RECT, uselessHackyView);
  }

  public void addTouchDelegate(@NonNull TouchDelegate touchDelegate) {
    mTouchDelegates.add(touchDelegate);
  }

  public void removeTouchDelegate(TouchDelegate touchDelegate) {
    mTouchDelegates.remove(touchDelegate);
    if (mCurrentTouchDelegate == touchDelegate) {
      mCurrentTouchDelegate = null;
    }
  }

  public void clearTouchDelegates() {
    mTouchDelegates.clear();
    mCurrentTouchDelegate = null;
  }

  @Override
  public boolean onTouchEvent(@NonNull MotionEvent event) {
    if (!mEnabled) return false;

    TouchDelegate delegate = null;

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
      for (int i = 0; i < mTouchDelegates.size(); i++) {
        TouchDelegate touchDelegate = mTouchDelegates.get(i);
        if (touchDelegate.onTouchEvent(event)) {
          mCurrentTouchDelegate = touchDelegate;
          return true;
        }
      }
      break;

    case MotionEvent.ACTION_MOVE:
      delegate = mCurrentTouchDelegate;
      break;

    case MotionEvent.ACTION_CANCEL:
    case MotionEvent.ACTION_UP:
      delegate = mCurrentTouchDelegate;
      mCurrentTouchDelegate = null;
      break;
    }

    return delegate != null && delegate.onTouchEvent(event);
  }

  public void setEnabled(boolean enabled) {
    mEnabled = enabled;
  }
}

 

MainActivity

package com.mobilprogramlar.floadnt;

import androidx.appcompat.app.AppCompatActivity;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

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

        findViewById(R.id.pink_icon).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "Clicked pink Floating Action Button", Toast.LENGTH_SHORT).show();
            }
        });

        FloatingActionButton button = (FloatingActionButton) findViewById(R.id.setter);
        button.setSize(FloatingActionButton.SIZE_MINI);
        button.setColorNormalResId(R.color.pink);
        button.setColorPressedResId(R.color.pink_pressed);
        button.setIcon(R.drawable.ic_fab_star);
        button.setStrokeVisible(false);

        final View actionB = findViewById(R.id.action_b);

        FloatingActionButton actionC = new FloatingActionButton(getBaseContext());
        actionC.setTitle("Hide/Show Action above");
        actionC.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                actionB.setVisibility(actionB.getVisibility() == View.GONE ? View.VISIBLE : View.GONE);
            }
        });

        final FloatingActionsMenu menuMultipleActions = (FloatingActionsMenu) findViewById(R.id.multiple_actions);
        menuMultipleActions.addButton(actionC);

        final FloatingActionButton removeAction = (FloatingActionButton) findViewById(R.id.button_remove);
        removeAction.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ((FloatingActionsMenu) findViewById(R.id.multiple_actions_down)).removeButton(removeAction);
            }
        });

        ShapeDrawable drawable = new ShapeDrawable(new OvalShape());
        drawable.getPaint().setColor(getResources().getColor(R.color.white));
        ((FloatingActionButton) findViewById(R.id.setter_drawable)).setIconDrawable(drawable);

        final FloatingActionButton actionA = (FloatingActionButton) findViewById(R.id.action_a);
        actionA.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                actionA.setTitle("Action A clicked");
            }
        });

        findViewById(R.id.button_gone).setVisibility(View.GONE);

        final FloatingActionButton actionEnable = (FloatingActionButton) findViewById(R.id.action_enable);
        actionEnable.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                menuMultipleActions.setEnabled(!menuMultipleActions.isEnabled());
            }
        });

        FloatingActionsMenu rightLabels = (FloatingActionsMenu) findViewById(R.id.right_labels);
        FloatingActionButton addedOnce = new FloatingActionButton(this);
        addedOnce.setTitle("Added once");
        rightLabels.addButton(addedOnce);

        FloatingActionButton addedTwice = new FloatingActionButton(this);
        addedTwice.setTitle("Added twice");
        rightLabels.addButton(addedTwice);
        rightLabels.removeButton(addedTwice);
        rightLabels.addButton(addedTwice);
    }
}

 

 

Value dizininin altına attrss.xml, colors.xml, dimens.xml, ids.xml, string.xml ve styles.xml dosyalarını ekliyoruz.

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="FloatingActionButton">
        <attr name="fab_colorPressed" format="color"/>
        <attr name="fab_colorDisabled" format="color"/>
        <attr name="fab_colorNormal" format="color"/>
        <attr name="fab_icon" format="reference"/>
        <attr name="fab_size" format="enum">
            <enum name="normal" value="0"/>
            <enum name="mini" value="1"/>
        </attr>
        <attr name="fab_title" format="string"/>
        <attr name="fab_stroke_visible" format="boolean"/>
    </declare-styleable>
    <declare-styleable name="AddFloatingActionButton">
        <attr name="fab_plusIconColor" format="color"/>
    </declare-styleable>
    <declare-styleable name="FloatingActionsMenu">
        <attr name="fab_addButtonColorPressed" format="color"/>
        <attr name="fab_addButtonColorNormal" format="color"/>
        <attr name="fab_addButtonSize" format="enum">
            <enum name="normal" value="0"/>
            <enum name="mini" value="1"/>
        </attr>
        <attr name="fab_addButtonPlusIconColor" format="color"/>
        <attr name="fab_addButtonStrokeVisible" format="boolean"/>
        <attr name="fab_labelStyle" format="reference"/>
        <attr name="fab_labelsPosition" format="enum">
            <enum name="left" value="0"/>
            <enum name="right" value="1"/>
        </attr>
        <attr name="fab_expandDirection" format="enum">
            <enum name="up" value="0"/>
            <enum name="down" value="1"/>
            <enum name="left" value="2"/>
            <enum name="right" value="3"/>
        </attr>
    </declare-styleable>
</resources>

 

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#008577</color>
    <color name="colorPrimaryDark">#00574B</color>
    <color name="colorAccent">#D81B60</color>

    <color name="black_semi_transparent">#B2000000</color>
    <color name="background">#e5e5e5</color>
    <color name="half_black">#808080</color>
    <color name="white">#fafafa</color>
    <color name="white_pressed">#f1f1f1</color>
    <color name="pink">#e91e63</color>
    <color name="pink_pressed">#ec407a</color>
    <color name="blue_semi_transparent">#805677fc</color>
    <color name="blue_semi_transparent_pressed">#80738ffe</color>
</resources>

 

dimans.xml

<resources>
    <dimen name="fab_size_normal">56dp</dimen>
    <dimen name="fab_size_mini">40dp</dimen>

    <dimen name="fab_icon_size">24dp</dimen>

    <dimen name="fab_plus_icon_size">14dp</dimen>
    <dimen name="fab_plus_icon_stroke">2dp</dimen>

    <dimen name="fab_shadow_offset">3dp</dimen>
    <dimen name="fab_shadow_radius">9dp</dimen>

    <dimen name="fab_stroke_width">1dp</dimen>

    <dimen name="fab_actions_spacing">16dp</dimen>
    <dimen name="fab_labels_margin">8dp</dimen>
</resources>

 

ids.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="fab_expand_menu_button" type="id"/>
    <item name="fab_label" type="id"/>
</resources>

String.xml

<resources>
    <string name="app_name">Fload NT</string>
    <string name="text_below_button">Text below button</string>
</resources>

Styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="menu_labels_style">
        <item name="android:background">@drawable/fab_label_background</item>
        <item name="android:textColor">@color/white</item>
    </style>

</resources>

 

drawable klasörünün altına ise

fab_label_background.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/black_semi_transparent"/>
    <padding
        android:left="16dp"
        android:top="4dp"
        android:right="16dp"
        android:bottom="4dp"/>
    <corners
        android:radius="2dp"/>
</shape>

Ayrıca alttaki 3 resim dosyasını da drawable klasörü altına ekliyoruz.

farklı telefon boyutları için bu resimlerin faklı ebatlarını yazının sonunda ki dosyanın tamamını indirebileceğiniz linki verdiğimde oradan indirebilirsiniz.

fab bg mini

fab bg normal

ic fab star

Sonuç;

floadNt

Anlatılanların tamamının Android Studio daki kaynak kod ve reimleri aşağıdaki linkten indirebilirsiniz.

İndir

 

Android Uygulamaya İkon Ekleme

1.yol:  http://makeappicon.com   adrsinini kullanarak 1024×1024 (tavsiye boyut) boyutundaki resmi buraya yükleriz. Bu online site bizim yüklediğimiz resimi android(mdpi-hdpi-xhdpi..), apple ve apple watch …   için gerekli boyutlara ayarlar. Bize email olarak gönderir.

2. yol: Android Studioyu kullanarak boyut ayarlama.

Öncelikle şunu bilmemiz lazım, Android uygulamalarımızda ikon ic_launcher ismi ayarlanmış şekilde gelmektedir.

Adaptive Icon?

Android 8.0 (API 26 ve üstü), farklı cihaz modellerinde farklı şekillerde görüntülenebilen uyarlanabilir uygulama iconu sunar.Uygulama iconları artık iki katmandan oluşturulmaktadır. Bunun için Foreground Layer ve Background Layer oluşturulmaktadır. Bu sayede hareketli bir icon’a sahip olunabilmektedir.

Adaptive Icon Nasıl Oluşturulur?

Android Studio açılır ve ardından  File sekmesine tıklayın daha sonra New seçeneğini seçin. Yeni açılan sayfada Image Asset seçeneğini seçeceksiniz.

File –> New –> Image Asset 

 

asset 01

 

Sonrasında gelecek olan menüde isim standartlarına uyarak bir isim verilmelidir.

Foreground Layer

Foreground kısmına da ic_logoismi_foreground şeklinde isim verildikten sonra “Image”, “Clip Art” veya “Text” ekleyebiliriz. Eğer Image eklenecekse ekrandaki path bölümünden arkaplanı transparan olan uygulama logosunu “.png” “.jpeg” ya da “svg path” olarak verilebilir; ancak daha az yer kaplaması için “svg path” tercih edilmelidir.

   Eklenen uygulama iconunun nasıl görüneceğini preview ekranında görülebilecektir.Uygulama iconunun boyutunu Scalling kısmından değiştirilebilir. Eğer logonuz gölgeli değilse ortalanması için “Trim” açılmalıdır.Iconunuz daire çizgilerinin içinde fazla büyük görünüyor ise Resize kısmından boyutu düzenlenebilir.

foreground layer

 

Background Layer

Background layer kısmında ise uygulama iconunun arka planı nasıl gözükecekse ona göre değiştirilebilir. “Renk” ve “Image” seçeneklerinden birisi kullanılabilir.

background layer

 

Legacy

Bu kısımda Play Store iconunu, API 25 ve altındaki telefonlarda uygulamanın iconu nasıl gözükmesi gerektiği seçilir.(square,circle,vertical,horizontal)

legacy

 

Next?

Bu kısımda artık uygulama iconu için gerekli boyutları ve adaptive icon için gerekli xml dosyaları oluşturuldu.

 

Manifests’e Eklenmesi

Manifests dosyasında

android:roundIcon = “@mipmap/ic_launcher_round” 
android:icon= “@mipmap/ic_launcher”

attributelerini mipmap klasörü içerisinde oluşan iconadi.xml dosyaları seçilmelidir.

<application
   android:allowBackup="true"
   android:icon="@mipmap/ic_launcher"
   android:label="@string/app_name"
   android:roundIcon="@mipmap/ic_launcher_round"
   android:supportsRtl="true"
   android:theme="@style/AppTheme" />

 

Android Size Analizörü Kullanarak Uygulama Boyutunu Küçültme

Android Size Analyzer aracı, uygulamanızın boyutunu azaltmak için birçok stratejiyi tanımlamanın ve uygulamanın kolay bir yoludur. Hem bir Android Studio eklentisi hem de bağımsız bir JAR olarak mevcut.

Android Studio’daki eklenti pazarını (plugin marketplace) kullanarak, şekilde gösterildiği gibi Android Size Analyzer eklentisini indirebilirsiniz. Eklenti pazarını açmak ve eklentiyi yüklemek için aşağıdakileri yapın:

  1. File > Settings (ya da Mac’da, Android Studio > Preferences.)
  2. Son panelden Plugins’i seçin
  3. Marketplace tabına tıklatın.
  4. “Android Size Analyzer” eklentisini araryın,.
  5. Bulduğunuzda Install  analyzer eklentisinde instal tuşuna basın..

 

plugin marketplace

Marketplace sekmesindeki Android Size Analyzer eklentisi.

 

Kurduktan sonra Android Studioyu kapatıp açın.

Sonra Analyze / Analyze App Size…     çalıştırarak uygulamada yapılabilecek

optimizasyon önerilerini görebiliriz.

 

Kaynak: https://developer.android.com/topic/performance/reduce-apk-size

 

 

 

 

 

 

 

 

 

 

 

Api numarasını ve Android Sürüm adını Bulma

 

Android de Sensörlere ya da bazı özelliklere ulaşabilmek için yazılım sürümünü ve ismini bilmek gerektiğinde lazım olabilecek kodlar …

Toast.makeText(getApplicationContext(),”Apı ve Versiyon:”+versiyonOgren(),Toast.LENGTH_LONG).show();

//Mevcut Android Sürüm Verileri(www.ossmatematik.com)
public static String versiyonOgren(){
    double ossmatematik = Double.parseDouble(Build.VERSION.RELEASE.replaceAll("(\\d+[.]\\d+)(.*)","$1"));
    String surumAdi="Desteklenmeyen";//Jelly bean altında veya Oreo üzerinde
    if(ossmatematik>=4.1 && ossmatematik<4.4)surumAdi="Jelly Bean";
    else if(ossmatematik<5)surumAdi="Kit Kat";
    else if(ossmatematik<6)surumAdi="Lollipop";
    else if(ossmatematik<7)surumAdi="Marshmallow";
    else if(ossmatematik<8)surumAdi="Nougat";
    else if(ossmatematik<9)surumAdi="Oreo";
    return "Sürüm Adı: "+surumAdi+" v"+ossmatematik+", API Seviyesi: "+Build.VERSION.SDK_INT;
}

Android sürümleri karşılaştırması burada

 

Android Platformunun belirli bir sürümünü çalıştıran cihazların göreceli sayısı hakkında bilgi ve

Platform Versiyonları burada

platform versiyonlari

 

Google Play Servislerini uygulama için hazır hale getirmek için build.gradle içine

yazılabilecek ekler;

google play servisleri

Güncel Hali

 

 

 

Google Play Hizmetlerini Androide Ekleme

Android uygulamalarınızı Google Play Servisleri ile entegre ederek, Haritalar, Drive ve Google+ gibi Google servislerine erişebilirsiniz. Uygulamalarınızı bu hizmetleri kullanacak şekilde ayarladıktan sonra, onlara erişmek genellikle basittir.

Kurulum işlemi birkaç adım gerektirir, ancak yalnızca bir kez gerçekleştirmeniz gerekir. Bu yazıda  Google Play Hizmetlerini Android uygulamalarıyla entegre etmeye çalışacağız.

Yazı boyunca, Eclipse ve Android Studio’daki uygulamaları Play Services ile entegre etmek için yapmanız gerekenleri özetleyeceğiz. Google Geliştirici Konsolu’na ve Keytool yardımcı programına erişmeniz gerekir.

Play Services’ı kurduğunuzda, geliştirme işleminin kendisi, uygulamalarınızın ne yapmasını istediğinize göre belirlenir. Ancak kurulum prosedürü aynı kalır. Platform hizmetlerine erişmek için client library (istemci kitaplığını) kullanarak, uygulamalarınız Google Play Store’daki otomatik güncellemelerden faydalanacaktır.

IDE’nizi açın ve Android SDK Manager’ı başlatın. Eclipse’de Window > Android > SDK Manager (SDK Yöneticisi)’ni seçin . Android Studio’da, SDK Manager araç çubuğu düğmesini tıklayın. Listede ilerleyin, Extras (Ekstralar) klasörünü genişletin ve Google Play Services (Google Play Servisleri’ni) seçin .

android play services sdk manager

Paketi kurmak ve istendiğinde lisansı kabul etmek için tıklayın. Android Studio’da geliştiriyorsanız,  Google Repository (Google Deposunu) da kurmanız gerekir .

Google Play Hizmet API’lerini kullandığınız uygulamaları test ederken, ideal olarak, onları fiziksel cihazlarda çalıştırmalısınız. Ancak, emülatörde test etmek mümkündür. Bunu yapmak için, Google API Platformunu yüklemeniz gerekecektir . Bunu, 17 ve üzeri API seviyelerinin herhangi biri için dizinde bulabilirsiniz.

android play services google apis

Platformu SDK Yöneticinizde bulun, kurun ve lisansı kabul edin. Bir uygulamayı Google Play Hizmetlerini kullanarak test etmek için bir AVD (Android Sanal Cihaz) ((Android Virtual Device) oluşturduğunuzda, hedef olarak Google API’ları seçin.

Eclipse’de geliştiriyorsanız, Play Services kitaplığını çalışma alanınıza kopyalamanız gerekir. İlk önce, bir dosya gezgini kullanarak bilgisayarınıza göz atın. Android SDK’nızı indirdiğiniz klasörde bulabilirsiniz

/extras/google/google_play_services/libproject/google-play-services_lib/

Bilgisayarınızdaki Android geliştirme dosyaları için kullandığınız bir yere kopyalayın. Kütüphaneyi kopyaladıktan sonra (sürümü SDK dizininde kullanmak yerine kopyalamanız gerekir), Eclipse’e geri dönün. Seç Al  dan  Dosya menüsünden. Expand Android klasörü seçin Existing Android Code Into Workspace (Mevcut Android Kod içine Workspace) ve İleri ye tıklayın .

android play services import library

Click Browse  (Gözat) düğmesini ve içine Play Services library  (Play Hizmetleri kütüphane) kopyalanan konuma gidin. Kopyaladığınız klasörü seçin ve almak için Son’a tıklayın . Paketi Package Explorer (Paket Gezgini)’nde görünecektir.

android play services import play project

Artık Play Services kaynaklarıyla geliştirmeye başlayabilirsiniz. IDE’nizde yeni bir Android projesi oluşturun.Çalışma alanınızda bir projeniz olduğunda, içindeki Play Services kaynaklarına başvurmanız gerekir.

Android Studio’da, uygulama projeniz için modülde build.gradle dosyasına bir inşa kuralı eklemeniz gerekir . Bu dependenciesbölümde aşağıdaki sözdizimini kullanın:

compile ‘com.google.android.gms:play-services:7.0.0’

Numarayı Play Services’ın en son sürümüne kullandığınızdan emin olun. Kütüphane güncellendiğinde bunu güncellemeniz gerekir. Dosyayı kaydedin ve Sync Project with Gradle Files (Projeyi Gradle Files ile Eşitle) düğmesine tıklayın.

6.5 sürümünden beri komple kütüphaneyi (çok büyük) veya sadece ihtiyacınız olan modülleri (En İyi Seçenek) ekleyebilirsiniz. Yani, yalnızca Google Haritalar ve Analytics’e ihtiyacınız varsa, önceki örneği aşağıdaki ile değiştirebilirsiniz:

dependencies { compile 'com.google.android.gms:play-services-base:7.0.0'
compile 'com.google.android.gms:play-services-maps:7.0.0'
}

Google Play Hizmetlerinin en yeni sürümünü burada bulabilirsiniz. Tam listesini burada bulabilirsiniz.

  1. Go to File -> Project Structure
  2. Project Settings‘ i seç
  3. Dependencies‘ Tabını seç
  4. +‘  ya tıkla ve ‘1.Library Dependencies‘ i seç
  5.  com.google.android.gms:play-services cümlesini arattır.
  6. Son versiyonu seç ve ‘OK‘ a tıkla

Eclipse’de Paket Gezgini’nde projeyi seçin, sağ tıklayın veya Project  (Proje) menüsünü seçin ve Properties (Özellikler)’i seçin . Android i seçip  sonra soldaki  Library  (Kütüphane) bölümündeki library yi seçerek Add  (Ekle) tıkla.

android play services add library

Paket Listesi burada 

Açılan pencereden Google Play Hizmetleri kütüphanesini seçin ve eklemek için Tamam’ı tıklayın . Apply (Uygula) ve  Tamam’a tıklayın .

android play services apply library

Hangi IDE’yi kullanıyorsanız kullanın, manifest dosyanıza Play Services meta-data eklemeniz gerekir. Projenin manifest dosyasını açın ve application  öğesinin içine meta-data öğesini ekleyin:

meta-data android:name=”com.google.android.gms.version”

android:value=”@integer/google_play_services_version”

Proguard kullanıyorsanız, bir istisna oluşturmanız gerekir. Daha fazla ayrıntı için Geliştirici Kılavuzuna bakın. Google Play Hizmet API’lerine genel bir bakış için Paket Dizini’ne göz atın .

Uygulama kodunuzda atmanız gereken işlem adımları, Play Services ile hangi işlevselliği uygulamak istediğinize bağlı olacaktır. Aşağıdaki bölümlerde bazı genel düşünceler ve adımlar açıklanmaktadır.

Güncellemeler Google Play Store üzerinden yayınlansa da, Google Play Hizmetleri ile herhangi bir işlem yapmayı denemeden önce, kullanıcı cihazının hangi sürümünün yüklü olduğunu kontrol etmeniz önerilir.

Bkz Implementing GCM Client (Uygulama GCM Müşteri) bir mesafede olan bu kontrolleri nasıl uygulanacağı bir bakış için Geliştirici Kılavuzu’nda örnek kod Activitysınıfında. Aranacak yöntem çağrısı isGooglePlayServicesAvailable, aşağıdaki alıntıdaki gibi yardımcı bir yönteme ekleyebileceğiniz yöntemdir:

private boolean checkPlayServices() {
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
    //...
}

Play Services kaynaklarına eriştiğiniz örneği onCreateoluşturmayı denemeden önce ve içindeki yöntemi çağırabilirsiniz . Kullanıcı cihazında kurulu gerekli kaynaklar yoksa, onlardan Google Play Store aracılığıyla istenir. GoogleAPIClientonResume

Kullanıcı cihazındaki destek düzeyini kontrol ettikten sonra GoogleAPIClient , Google Play kaynaklarında çağrılacak sınıfın bir örneğini oluşturabilirsiniz . Aşağıdaki örnek kod bunu göstermektedir ve buna dahil edilebilir onCreate:

GoogleApiClient myClient = new GoogleApiClient.Builder(this)
.addApi(Plus.API)
.addScope(Plus.SCOPE_PLUS_PROFILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();

Bu, uygulamanızı Plus.APIalıntıdan görebileceğiniz gibi Google+ hizmetlerine erişmek için hazırlar . addScopeHattı, uygulamanın ne bağlı olarak değişecektir. Bu kod ayrıca bağlantı işlemi için geri aramaları ayarlar. Sınıfınız aşağıdaki arayüzleri uygulayabilir:

public class MainActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener

Sınıf daha sonra uygulayabilirsiniz onConnectedve onConnectionSuspendedPlay Hizmetleri bağlantı değişiklikleri işlemek için geri aramalar.

Kullanıcının oturum açması gerektiği durumlarda olduğu gibi Play Services’e bağlanmadaki başarısızlıklarla başa çıkmak için, sınıfınız onConnectionFailed tipik hataları çözmek için çeşitli standart yöntemlere erişmek için de uygulayabilir . Bu yöntemlerden bazıları onActivityResult, kullanıcı uygulamaya geri döndüğünde yöntemin çalışmasına neden olur , böylece oraya bağlanmak için yeniden giriş yapabilirsiniz.

Genel olarak, Activity sınıfınız  aşağıdaki alıntılarda olduğu gibi sınıf üzerinden Play Services’e bağlanmalı ve sınıf yoluyla onStartbağlantısını kesmelidir:onStopGoogleAPIClient

myClient.connect();

Google+ dahil olmak üzere bazı Oynatma Servislerinde erişim için kayıt olmanız gerekir. Bunu yapmak için, Google API Konsolu’na giriş yapın , Create Project (Proje Oluştur)’u tıklayın  ve bir ad girin. Projeyi oluşturduktan sonra, konsoldaki projeye yönlendirilmelisiniz.

API menü öğesini seçin, listede Google+ API’yi bulun ve etkinleştirmek için düğmeye tıklayın. Lisansı kabul ettikten sonra durumun ON (AÇIK) olması gerekir . API listesine tıklamak, onunla neler yapabileceğinize dair genel bir bakış sunar.

Ardından, Credentials (Kimlik Bilgileri)’ni seçin   ve Create New Client ID (Yeni Müşteri Kimliği Oluştur)’u tıklayın. Installed application (Yüklü uygulama) nın radyo düğmesini seçin, Android’i türü olarak ve uygulama ayrıntıları girin. Şimdi bir SHA1 sertifikası oluşturmak için Keytool kaynağını kullanmanız gerekir.

Geliştirme sırasında, aşağıdaki kodu bir terminale girerek hata ayıklama anahtar deposunu kullanabilirsiniz:

keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v

Bunun hata ayıklama anahtar deponuz için doğru konum olduğundan emin olmanız gerekir, değilse yolu değiştirin. Bu komutu çalıştırdığınızda, sizden şifre istenir. androidHata ayıklama anahtar deposu için Enter  ve parmak izi terminale çıkarılmalıdır.

Signing certificate fingerprint ((İmzalama sertifikası parmak izi))  kutusu içerisindeki API konsoluna SHA1satırını kopyala ve yapıştırın.

Gerekirse derinlemesine bağlantıyı etkinleştirin ve ardından ID (kimliği) oluşturmak için düğmeye tıklayın. Client ID for Android Application ( Android Uygulaması için Müşteri Kimliği) başlıklı bir bölüm görünecektir . ID (Kimliğinizi)’nizi uygulama kodunuzda kullanmanız gerekmez, ancak bir kopyasını kendi kayıtlarınız için saklamak isteyebilirsiniz.

Uygulama kodunuzdaki Play Services API’lerini çağırmadan önce, projenizin bildirim dosyasına uygun izinleri eklemeniz gerekir. Aşağıdaki örnekler birkaç tipik kullanım durumu göstermektedir, ancak kendi projeniz için uygun izinleri seçmeniz gerekecektir:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />

Projeniz şimdi ihtiyacınız olan Play Services API’lerini arayacak şekilde yapılandırılmalıdır. ActivityUygulamalarınızın ne yaptığına bağlı olarak sınıflarınızı farklı bir şekilde yapılandırmanız gerekecektir . Bununla ilgili daha fazla bilgi için Developer Guide(Geliştirici Kılavuzuna) bakın.

Mevcut Oyun Servislerinden bazılarına başlamak için aşağıdaki kılavuzları incelemeyi unutmayın:

Erişmek istediğiniz Google hizmetleri Play Services kütüphanesinin bir parçası değilse, Google’ın REST API’sini kullanarak bunlara erişebilirsiniz.

Android uygulamalarında Google Play Servisleri ile birçok olasılık var. Oyun oynamaktan konum ve haritalama hizmetlerine kadar, uygulamalarınız kendi kullanıcı arayüzleriniz ve işlevleriniz bağlamında mevcut platform özelliklerinden faydalanabilir.

Kurulum işlemi biraz zahmetli görünebilir, ancak bir kez kurduğunuzda, bu hizmetleri kullanıcılarınıza sunmaya odaklanabilirsiniz.

https://code.tutsplus.com/tutorials/integrating-google-play-services-on-android–cms-19828