diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java index 5dd06f903..339d8b368 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java @@ -3,7 +3,6 @@ package com.topjohnwu.magisk; import android.animation.Animator; import android.animation.ValueAnimator; import android.app.ProgressDialog; -import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; @@ -136,7 +135,7 @@ public class MagiskFragment extends Fragment private boolean verity = keepVerityChkbox.isChecked(); @Override - public void onDownloadDone(Uri uri, Context context) { + public void onDownloadDone(Uri uri) { if (Shell.rootAccess()) { magiskManager.shell.su_raw( "rm -f /dev/.magisk", @@ -144,7 +143,7 @@ public class MagiskFragment extends Fragment "echo \"KEEPFORCEENCRYPT=" + String.valueOf(enc) + "\" >> /dev/.magisk", "echo \"KEEPVERITY=" + String.valueOf(verity) + "\" >> /dev/.magisk" ); - startActivity(new Intent(context, FlashActivity.class).setData(uri)); + startActivity(new Intent(getActivity(), FlashActivity.class).setData(uri)); } else { Utils.showUriSnack(getActivity(), uri); } diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java index 69888a704..2835c8fdc 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java @@ -2,7 +2,6 @@ package com.topjohnwu.magisk; import android.os.Bundle; import android.support.annotation.Nullable; -import android.support.v4.view.MenuItemCompat; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -14,18 +13,11 @@ import android.widget.SearchView; import android.widget.TextView; import com.topjohnwu.magisk.adapters.ReposAdapter; -import com.topjohnwu.magisk.adapters.SimpleSectionedRecyclerViewAdapter; import com.topjohnwu.magisk.asyncs.LoadRepos; -import com.topjohnwu.magisk.asyncs.ParallelTask; import com.topjohnwu.magisk.components.Fragment; -import com.topjohnwu.magisk.module.Module; -import com.topjohnwu.magisk.module.Repo; import com.topjohnwu.magisk.utils.CallbackEvent; import com.topjohnwu.magisk.utils.Logger; -import java.util.ArrayList; -import java.util.List; - import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; @@ -37,16 +29,7 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener mUpdateRepos = new ArrayList<>(); - private List mInstalledRepos = new ArrayList<>(); - private List mOthersRepos = new ArrayList<>(); - private List fUpdateRepos = new ArrayList<>(); - private List fInstalledRepos = new ArrayList<>(); - private List fOthersRepos = new ArrayList<>(); - - private SimpleSectionedRecyclerViewAdapter mSectionedAdapter; - - private SearchView.OnQueryTextListener searchListener; + private ReposAdapter adapter; @Override public void onCreate(@Nullable Bundle savedInstanceState) { @@ -60,10 +43,9 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener event) { Logger.dev("ReposFragment: UI refresh triggered"); - reloadRepos(); - updateUI(); + if (getApplication().repoMap.isEmpty()) { + recyclerView.setVisibility(View.GONE); + emptyRv.setVisibility(View.VISIBLE); + } else { + adapter.filter(getApplication().moduleMap, ""); + recyclerView.setVisibility(View.VISIBLE); + emptyRv.setVisibility(View.GONE); + mSwipeRefreshLayout.setRefreshing(false); + } } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu_repo, menu); - SearchView search = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.repo_search)); - search.setOnQueryTextListener(searchListener); + SearchView search = (SearchView) menu.findItem(R.id.repo_search).getActionView(); + search.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + adapter.filter(getApplication().moduleMap, newText); + return false; + } + }); } @Override @@ -125,92 +111,4 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener module.getVersionCode()) { - mUpdateRepos.add(repo); - } else { - mInstalledRepos.add(repo); - } - } else { - mOthersRepos.add(repo); - } - } - fUpdateRepos.clear(); - fInstalledRepos.clear(); - fOthersRepos.clear(); - fUpdateRepos.addAll(mUpdateRepos); - fInstalledRepos.addAll(mInstalledRepos); - fOthersRepos.addAll(mOthersRepos); - } - - private void updateUI() { - if (fUpdateRepos.size() + fInstalledRepos.size() + fOthersRepos.size() == 0) { - emptyRv.setVisibility(View.VISIBLE); - recyclerView.setVisibility(View.GONE); - } else { - List sections = new ArrayList<>(); - if (!fUpdateRepos.isEmpty()) { - sections.add(new SimpleSectionedRecyclerViewAdapter.Section(0, getString(R.string.update_available))); - } - if (!fInstalledRepos.isEmpty()) { - sections.add(new SimpleSectionedRecyclerViewAdapter.Section(fUpdateRepos.size(), getString(R.string.installed))); - } - if (!fOthersRepos.isEmpty()) { - sections.add(new SimpleSectionedRecyclerViewAdapter.Section(fUpdateRepos.size() + fInstalledRepos.size(), getString(R.string.not_installed))); - } - SimpleSectionedRecyclerViewAdapter.Section[] array = sections.toArray(new SimpleSectionedRecyclerViewAdapter.Section[sections.size()]); - mSectionedAdapter.setSections(array); - emptyRv.setVisibility(View.GONE); - recyclerView.setVisibility(View.VISIBLE); - } - mSwipeRefreshLayout.setRefreshing(false); - } - - private class FilterApps extends ParallelTask { - @Override - protected Void doInBackground(String... strings) { - String newText = strings[0]; - fUpdateRepos.clear(); - fInstalledRepos.clear(); - fOthersRepos.clear(); - for (Repo repo: mUpdateRepos) { - if (repo.getName().toLowerCase().contains(newText.toLowerCase()) - || repo.getAuthor().toLowerCase().contains(newText.toLowerCase()) - || repo.getDescription().toLowerCase().contains(newText.toLowerCase()) - ) { - fUpdateRepos.add(repo); - } - } - for (Repo repo: mInstalledRepos) { - if (repo.getName().toLowerCase().contains(newText.toLowerCase()) - || repo.getAuthor().toLowerCase().contains(newText.toLowerCase()) - || repo.getDescription().toLowerCase().contains(newText.toLowerCase()) - ) { - fInstalledRepos.add(repo); - } - } - for (Repo repo: mOthersRepos) { - if (repo.getName().toLowerCase().contains(newText.toLowerCase()) - || repo.getAuthor().toLowerCase().contains(newText.toLowerCase()) - || repo.getDescription().toLowerCase().contains(newText.toLowerCase()) - ) { - fOthersRepos.add(repo); - } - } - return null; - } - - @Override - protected void onPostExecute(Void v) { - updateUI(); - } - } - } diff --git a/app/src/main/java/com/topjohnwu/magisk/adapters/ReposAdapter.java b/app/src/main/java/com/topjohnwu/magisk/adapters/ReposAdapter.java index be827b9de..442489b31 100644 --- a/app/src/main/java/com/topjohnwu/magisk/adapters/ReposAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/adapters/ReposAdapter.java @@ -16,96 +16,184 @@ import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.asyncs.ProcessRepoZip; import com.topjohnwu.magisk.components.AlertDialogBuilder; import com.topjohnwu.magisk.components.MarkDownWindow; +import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.module.Repo; import com.topjohnwu.magisk.receivers.DownloadReceiver; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.ValueSortedMap; +import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; -public class ReposAdapter extends RecyclerView.Adapter { +public class ReposAdapter extends RecyclerView.Adapter { + + private static final int SECTION_TYPE = 0; + private static final int REPO_TYPE = 1; private List mUpdateRepos, mInstalledRepos, mOthersRepos; - private Context mContext; + private int[] sectionList; + private int size; + private ValueSortedMap repoMap; - public ReposAdapter(List update, List installed, List others) { - mUpdateRepos = update; - mInstalledRepos = installed; - mOthersRepos = others; + public ReposAdapter(ValueSortedMap map) { + repoMap = map; + mUpdateRepos = new ArrayList<>(); + mInstalledRepos = new ArrayList<>(); + mOthersRepos = new ArrayList<>(); + sectionList = new int[3]; + size = 0; } @Override - public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - mContext = parent.getContext(); - View v = LayoutInflater.from(mContext).inflate(R.layout.list_item_repo, parent, false); - return new ViewHolder(v); + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + Context context = parent.getContext(); + View v; + RecyclerView.ViewHolder holder = null; + switch (viewType) { + case SECTION_TYPE: + v = LayoutInflater.from(context).inflate(R.layout.section, parent, false); + holder = new SectionHolder(v); + break; + case REPO_TYPE: + v = LayoutInflater.from(context).inflate(R.layout.list_item_repo, parent, false); + holder = new RepoHolder(v); + break; + } + return holder; } @Override - public void onBindViewHolder(final ViewHolder holder, int position) { - Repo repo = getItem(position); + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + Context context = holder.itemView.getContext(); + switch (getItemViewType(position)) { + case SECTION_TYPE: + SectionHolder section = (SectionHolder) holder; + if (position == sectionList[0]) { + section.sectionText.setText(context.getString(R.string.update_available)); + } else if (position == sectionList[1]) { + section.sectionText.setText(context.getString(R.string.installed)); + } else { + section.sectionText.setText(context.getString(R.string.not_installed)); + } + break; + case REPO_TYPE: + RepoHolder repoHolder = (RepoHolder) holder; + Repo repo = getRepo(position); + repoHolder.title.setText(repo.getName()); + repoHolder.versionName.setText(repo.getVersion()); + String author = repo.getAuthor(); + repoHolder.author.setText(TextUtils.isEmpty(author) ? null : context.getString(R.string.author, author)); + repoHolder.description.setText(repo.getDescription()); - holder.title.setText(repo.getName()); - holder.versionName.setText(repo.getVersion()); - String author = repo.getAuthor(); - holder.author.setText(TextUtils.isEmpty(author) ? null : mContext.getString(R.string.author, author)); - holder.description.setText(repo.getDescription()); + repoHolder.infoLayout.setOnClickListener(v -> new MarkDownWindow(null, repo.getDetailUrl(), context)); - holder.infoLayout.setOnClickListener(v -> new MarkDownWindow(null, repo.getDetailUrl(), mContext)); + repoHolder.downloadImage.setOnClickListener(v -> { + String filename = repo.getName() + "-" + repo.getVersion() + ".zip"; + new AlertDialogBuilder(context) + .setTitle(context.getString(R.string.repo_install_title, repo.getName())) + .setMessage(context.getString(R.string.repo_install_msg, filename)) + .setCancelable(true) + .setPositiveButton(R.string.install, (d, i) -> Utils.dlAndReceive( + context, + new DownloadReceiver() { + @Override + public void onDownloadDone(Uri uri) { + new ProcessRepoZip((Activity) context, uri, true).exec(); + } + }, + repo.getZipUrl(), + Utils.getLegalFilename(filename))) + .setNeutralButton(R.string.download, (d, i) -> Utils.dlAndReceive( + context, + new DownloadReceiver() { + @Override + public void onDownloadDone(Uri uri) { + new ProcessRepoZip((Activity) context, uri, false).exec(); + } + }, + repo.getZipUrl(), + Utils.getLegalFilename(filename))) + .setNegativeButton(R.string.no_thanks, null) + .show(); + }); + break; + } + } - holder.downloadImage.setOnClickListener(v -> { - String filename = repo.getName() + "-" + repo.getVersion() + ".zip"; - new AlertDialogBuilder(mContext) - .setTitle(mContext.getString(R.string.repo_install_title, repo.getName())) - .setMessage(mContext.getString(R.string.repo_install_msg, filename)) - .setCancelable(true) - .setPositiveButton(R.string.install, (d, i) -> Utils.dlAndReceive( - mContext, - new DownloadReceiver() { - @Override - public void onDownloadDone(Uri uri, Context context) { - new ProcessRepoZip((Activity) mContext, uri, true).exec(); - } - }, - repo.getZipUrl(), - Utils.getLegalFilename(filename))) - .setNeutralButton(R.string.download, (d, i) -> Utils.dlAndReceive( - mContext, - new DownloadReceiver() { - @Override - public void onDownloadDone(Uri uri, Context context) { - new ProcessRepoZip((Activity) mContext, uri, false).exec(); - } - }, - repo.getZipUrl(), - Utils.getLegalFilename(filename))) - .setNegativeButton(R.string.no_thanks, null) - .show(); - }); + @Override + public int getItemViewType(int position) { + for (int i : sectionList) { + if (position == i) + return SECTION_TYPE; + } + return REPO_TYPE; } @Override public int getItemCount() { - return mUpdateRepos.size() + mInstalledRepos.size() + mOthersRepos.size(); + return size; } - private Repo getItem(int position) { - if (position >= mUpdateRepos.size()) { - position -= mUpdateRepos.size(); - if (position >= mInstalledRepos.size()) { - position -= mInstalledRepos.size(); - return mOthersRepos.get(position); - } else { - return mInstalledRepos.get(position); + public void filter(ValueSortedMap moduleMap, String s) { + mUpdateRepos.clear(); + mInstalledRepos.clear(); + mOthersRepos.clear(); + sectionList[0] = sectionList[1] = sectionList[2] = 0; + for (Repo repo : repoMap.values()) { + if (repo.getName().toLowerCase().contains(s.toLowerCase()) + || repo.getAuthor().toLowerCase().contains(s.toLowerCase()) + || repo.getDescription().toLowerCase().contains(s.toLowerCase()) + ) { + // Passed the filter + Module module = moduleMap.get(repo.getId()); + if (module != null) { + if (repo.getVersionCode() > module.getVersionCode()) { + // Updates + mUpdateRepos.add(repo); + } else { + mInstalledRepos.add(repo); + } + } else { + mOthersRepos.add(repo); + } } - } else { - return mUpdateRepos.get(position); + } + + sectionList[0] = mUpdateRepos.isEmpty() ? -1 : 0; + size = mUpdateRepos.isEmpty() ? 0 : mUpdateRepos.size() + 1; + sectionList[1] = mInstalledRepos.isEmpty() ? -1 : size; + size += mInstalledRepos.isEmpty() ? 0 : mInstalledRepos.size() + 1; + sectionList[2] = mOthersRepos.isEmpty() ? -1 : size; + size += mOthersRepos.isEmpty() ? 0 : mOthersRepos.size() + 1; + + notifyDataSetChanged(); + } + + private Repo getRepo(int position) { + if (!mUpdateRepos.isEmpty()) position -= 1; + if (position < mUpdateRepos.size()) return mUpdateRepos.get(position); + position -= mUpdateRepos.size(); + if (!mInstalledRepos.isEmpty()) position -= 1; + if (position < mInstalledRepos.size()) return mInstalledRepos.get(position); + position -= mInstalledRepos.size(); + if (!mOthersRepos.isEmpty()) position -= 1; + return mOthersRepos.get(position); + } + + static class SectionHolder extends RecyclerView.ViewHolder { + + @BindView(R.id.section_text) TextView sectionText; + + SectionHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); } } - static class ViewHolder extends RecyclerView.ViewHolder { + static class RepoHolder extends RecyclerView.ViewHolder { @BindView(R.id.title) TextView title; @BindView(R.id.version_name) TextView versionName; @@ -114,7 +202,7 @@ public class ReposAdapter extends RecyclerView.Adapter @BindView(R.id.info_layout) LinearLayout infoLayout; @BindView(R.id.download) ImageView downloadImage; - ViewHolder(View itemView) { + RepoHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } diff --git a/app/src/main/java/com/topjohnwu/magisk/adapters/SimpleSectionedRecyclerViewAdapter.java b/app/src/main/java/com/topjohnwu/magisk/adapters/SimpleSectionedRecyclerViewAdapter.java deleted file mode 100644 index 7ba161e21..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/adapters/SimpleSectionedRecyclerViewAdapter.java +++ /dev/null @@ -1,178 +0,0 @@ -package com.topjohnwu.magisk.adapters; - -import android.support.v7.widget.RecyclerView; -import android.util.SparseArray; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import java.util.Arrays; -import java.util.Comparator; - -public class SimpleSectionedRecyclerViewAdapter extends RecyclerView.Adapter { - - private static final int SECTION_TYPE = 0; - - private boolean mValid = true; - private int mSectionResourceId; - private int mTextResourceId; - private RecyclerView.Adapter mBaseAdapter; - private SparseArray
mSections = new SparseArray
(); - - - public SimpleSectionedRecyclerViewAdapter(int sectionResourceId, int textResourceId, - RecyclerView.Adapter baseAdapter) { - - mSectionResourceId = sectionResourceId; - mTextResourceId = textResourceId; - mBaseAdapter = baseAdapter; - - mBaseAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { - @Override - public void onChanged() { - mValid = mBaseAdapter.getItemCount()>0; - notifyDataSetChanged(); - } - - @Override - public void onItemRangeChanged(int positionStart, int itemCount) { - mValid = mBaseAdapter.getItemCount()>0; - notifyItemRangeChanged(positionStart, itemCount); - } - - @Override - public void onItemRangeInserted(int positionStart, int itemCount) { - mValid = mBaseAdapter.getItemCount()>0; - notifyItemRangeInserted(positionStart, itemCount); - } - - @Override - public void onItemRangeRemoved(int positionStart, int itemCount) { - mValid = mBaseAdapter.getItemCount()>0; - notifyItemRangeRemoved(positionStart, itemCount); - } - }); - } - - - public static class SectionViewHolder extends RecyclerView.ViewHolder { - - public TextView title; - - public SectionViewHolder(View view, int mTextResourceid) { - super(view); - title = (TextView) view.findViewById(mTextResourceid); - } - } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int typeView) { - if (typeView == SECTION_TYPE) { - View view = LayoutInflater.from(parent.getContext()).inflate(mSectionResourceId, parent, false); - return new SectionViewHolder(view,mTextResourceId); - }else{ - return mBaseAdapter.onCreateViewHolder(parent, typeView -1); - } - } - - @Override - public void onBindViewHolder(RecyclerView.ViewHolder sectionViewHolder, int position) { - if (isSectionHeaderPosition(position)) { - ((SectionViewHolder)sectionViewHolder).title.setText(mSections.get(position).title); - }else{ - mBaseAdapter.onBindViewHolder(sectionViewHolder,sectionedPositionToPosition(position)); - } - - } - - @Override - public int getItemViewType(int position) { - return isSectionHeaderPosition(position) - ? SECTION_TYPE - : mBaseAdapter.getItemViewType(sectionedPositionToPosition(position)) +1 ; - } - - - public static class Section { - int firstPosition; - int sectionedPosition; - CharSequence title; - - public Section(int firstPosition, CharSequence title) { - this.firstPosition = firstPosition; - this.title = title; - } - - public CharSequence getTitle() { - return title; - } - } - - - public void setSections(Section[] sections) { - mSections.clear(); - - Arrays.sort(sections, new Comparator
() { - @Override - public int compare(Section o, Section o1) { - return (o.firstPosition == o1.firstPosition) - ? 0 - : ((o.firstPosition < o1.firstPosition) ? -1 : 1); - } - }); - - int offset = 0; // offset positions for the headers we're adding - for (Section section : sections) { - section.sectionedPosition = section.firstPosition + offset; - mSections.append(section.sectionedPosition, section); - ++offset; - } - - notifyDataSetChanged(); - } - - public int positionToSectionedPosition(int position) { - int offset = 0; - for (int i = 0; i < mSections.size(); i++) { - if (mSections.valueAt(i).firstPosition > position) { - break; - } - ++offset; - } - return position + offset; - } - - public int sectionedPositionToPosition(int sectionedPosition) { - if (isSectionHeaderPosition(sectionedPosition)) { - return RecyclerView.NO_POSITION; - } - - int offset = 0; - for (int i = 0; i < mSections.size(); i++) { - if (mSections.valueAt(i).sectionedPosition > sectionedPosition) { - break; - } - --offset; - } - return sectionedPosition + offset; - } - - public boolean isSectionHeaderPosition(int position) { - return mSections.get(position) != null; - } - - - @Override - public long getItemId(int position) { - return isSectionHeaderPosition(position) - ? Integer.MAX_VALUE - mSections.indexOfKey(position) - : mBaseAdapter.getItemId(sectionedPositionToPosition(position)); - } - - @Override - public int getItemCount() { - return (mValid ? mBaseAdapter.getItemCount() + mSections.size() : 0); - } - -} diff --git a/app/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java b/app/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java index 85149f3e5..76241a5db 100644 --- a/app/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java +++ b/app/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java @@ -31,7 +31,7 @@ public abstract class DownloadReceiver extends BroadcastReceiver { switch (status) { case DownloadManager.STATUS_SUCCESSFUL: Uri uri = Uri.parse(c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))); - onDownloadDone(uri, context); + onDownloadDone(uri); break; default: Toast.makeText(context, R.string.download_file_error, Toast.LENGTH_LONG).show(); @@ -52,5 +52,5 @@ public abstract class DownloadReceiver extends BroadcastReceiver { mFilename = filename; } - public abstract void onDownloadDone(Uri uri, Context context); + public abstract void onDownloadDone(Uri uri); } diff --git a/app/src/main/java/com/topjohnwu/magisk/receivers/ManagerUpdate.java b/app/src/main/java/com/topjohnwu/magisk/receivers/ManagerUpdate.java index d26a1d56e..a2a5f14a7 100644 --- a/app/src/main/java/com/topjohnwu/magisk/receivers/ManagerUpdate.java +++ b/app/src/main/java/com/topjohnwu/magisk/receivers/ManagerUpdate.java @@ -18,7 +18,7 @@ public class ManagerUpdate extends BroadcastReceiver { context, new DownloadReceiver() { @Override - public void onDownloadDone(Uri uri, Context context) { + public void onDownloadDone(Uri uri) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE); install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); diff --git a/build.gradle b/build.gradle index bfd7d5093..ea3b1c75b 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { maven { url "https://maven.google.com" } } dependencies { - classpath 'com.android.tools.build:gradle:3.0.0-alpha6' + classpath 'com.android.tools.build:gradle:3.0.0-alpha7' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files